feat: downloadFullImage for full graph.

This commit is contained in:
Yanyan-Wang 2020-04-13 19:48:40 +08:00 committed by Yanyan Wang
parent f82d5ecfd2
commit b56c83d3eb
4 changed files with 177 additions and 38 deletions

View File

@ -50,7 +50,7 @@
"site:deploy": "npm run site:build && gh-pages -d public",
"start": "npm run site:develop",
"test": "jest",
"test-live": "DEBUG_MODE=1 jest --watch ./tests/unit/plugins/minimap-spec.ts",
"test-live": "DEBUG_MODE=1 jest --watch ./tests/unit/graph/graph-spec.ts",
"lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx",
"watch": "father build -w",
"cdn": "antv-bin upload -n @antv/g6"

View File

@ -10,6 +10,7 @@ import deepMix from '@antv/util/lib/deep-mix';
import each from '@antv/util/lib/each';
import isPlainObject from '@antv/util/lib/is-plain-object';
import isString from '@antv/util/lib/is-string';
import isNumber from '@antv/util/lib/is-number';
import {
GraphAnimateConfig,
GraphOptions,
@ -46,6 +47,7 @@ import {
ViewController,
} from './controller';
import PluginBase from '../plugins/base';
import createDom from '@antv/dom-util/lib/create-dom';
const NODE = 'node';
const SVG = 'svg';
@ -1364,7 +1366,91 @@ export default class Graph extends EventEmitter implements IGraph {
}
/**
*
*
* @param {String} name
*/
public downloadFullImage(name?: string, imageConfig?: { backgroundColor?: string, padding?: number | number[]}): void {
const bbox = this.get('group').getCanvasBBox();
const height = bbox.height;
const width = bbox.width;
const renderer = this.get('renderer');
const vContainerDOM = createDom('<div id="test"></div>');
let backgroundColor = imageConfig ? imageConfig.backgroundColor : undefined;
let padding = imageConfig ? imageConfig.padding : undefined;
if (!padding) padding = [ 0, 0, 0, 0 ];
else if (isNumber(padding)) padding = [padding, padding, padding, padding];
const vHeight = height + padding[0] + padding[2];
const vWidth = width + padding[1] + padding[3];
const canvasOptions = {
container: vContainerDOM,
height: vHeight,
width: vWidth
};
const vCanvas = renderer === 'svg' ? new GSVGCanvas(canvasOptions) : new GCanvas(canvasOptions);
const group = this.get('group');
const vGroup = group.clone();
let matrix = vGroup.getMatrix();
if (!matrix) matrix = mat3.create();
const centerX = (bbox.maxX + bbox.minX) / 2;
const centerY = (bbox.maxY + bbox.minY) / 2;
mat3.translate(matrix, matrix, [-centerX, -centerY]);
mat3.translate(matrix, matrix, [width / 2 + padding[3], height / 2 + padding[0]]);
vGroup.resetMatrix();
vGroup.setMatrix(matrix);
vCanvas.add(vGroup);
const vCanvasEl = vCanvas.get('el');
setTimeout(() => {
const type = 'image/png';
let dataURL = '';
if (renderer === 'svg') {
const clone = vCanvasEl.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 {
let imageData;
const context = vCanvasEl.getContext('2d');
let compositeOperation;
if (backgroundColor) {
const pixelRatio = window.devicePixelRatio;
imageData = context.getImageData(0, 0, vWidth * pixelRatio, vHeight * pixelRatio);
compositeOperation = context.globalCompositeOperation;
context.globalCompositeOperation = "destination-over";
context.fillStyle = backgroundColor;
context.fillRect(0, 0, vWidth, vHeight);
}
dataURL = vCanvasEl.toDataURL(type);
if (backgroundColor) {
context.clearRect(0, 0, vWidth, vHeight);
context.putImageData(imageData, 0, 0);
context.globalCompositeOperation = compositeOperation;
}
}
const link: HTMLAnchorElement = document.createElement('a');
const fileName: string = (name || 'graph') + (renderer === 'svg' ? '.svg' : '.png');
this.dataURLToImage(dataURL, renderer, link, fileName);
const e = document.createEvent('MouseEvents');
e.initEvent('click', false, false);
link.dispatchEvent(e);
}, 16);
}
/**
*
* @param {String} name
*/
public downloadImage(name?: string, backgroundColor?: string): void {
@ -1380,41 +1466,7 @@ export default class Graph extends EventEmitter implements IGraph {
const link: HTMLAnchorElement = document.createElement('a');
setTimeout(() => {
const dataURL = self.toDataURL('image/png', backgroundColor);
if (typeof window !== 'undefined') {
if (window.Blob && window.URL && renderer !== 'svg') {
const arr = dataURL.split(',');
let mime = '';
if (arr && arr.length > 0) {
const match = arr[0].match(/:(.*?);/);
// eslint-disable-next-line prefer-destructuring
if (match && match.length >= 2) mime = 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', () => {
link.download = fileName;
link.href = window.URL.createObjectURL(blobObj);
});
}
} else {
link.addEventListener('click', function() {
link.download = fileName;
link.href = dataURL;
});
}
}
this.dataURLToImage(dataURL, renderer, link, fileName);
const e = document.createEvent('MouseEvents');
e.initEvent('click', false, false);
@ -1422,6 +1474,43 @@ export default class Graph extends EventEmitter implements IGraph {
}, 16);
}
private dataURLToImage(dataURL: string, renderer: string, link, fileName) {
if (typeof window !== 'undefined') {
if (window.Blob && window.URL && renderer !== 'svg') {
const arr = dataURL.split(',');
let mime = '';
if (arr && arr.length > 0) {
const match = arr[0].match(/:(.*?);/);
// eslint-disable-next-line prefer-destructuring
if (match && match.length >= 2) mime = 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', () => {
link.download = fileName;
link.href = window.URL.createObjectURL(blobObj);
});
}
} else {
link.addEventListener('click', function() {
link.download = fileName;
link.href = dataURL;
});
}
}
}
/**
*
* @param {object} cfg

View File

@ -495,11 +495,17 @@ export interface IGraph extends EventEmitter {
toDataURL(type?: string, backgroundColor?: string): string;
/**
*
*
* @param {String} name
*/
downloadImage(name?: string, backgroundColor?: string): void;
/**
*
* @param {String} name
*/
downloadFullImage(name?: string, imageConfig?: { backgroundColor?: string, padding?: number | number[]}): void;
// TODO 需要添加布局配置类型
/**
*

View File

@ -1375,4 +1375,48 @@ describe('auto rotate label on edge', () => {
expect(groupMatrix[6]).toBe(100);
expect(groupMatrix[7]).toBe(120);
});
});
describe('auto rotate label on edge', () => {
const graph = new Graph({
container: div,
width: 500,
height: 500,
modes: {
default: ['drag-node', 'zoom-canvas', 'drag-canvas'],
},
});
const data = {
nodes: [
{
id: 'node1',
x: 100,
y: 200,
},
{
id: 'node2',
x: 800,
y: 200,
},
],
edges: [
{
id: 'edge1',
target: 'node2',
source: 'node1',
},
],
};
it('downloadFullImage', () => {
graph.data(data);
graph.render();
graph.on('canvas:click', evt => {
graph.downloadFullImage('graph', {
backgroundColor: '#fff',
padding: [ 40, 10, 10, 10 ]
});
});
});
});