Skip to content

Commit

Permalink
feat: generate the image url of the full graph by graph.toFullDataUrl…
Browse files Browse the repository at this point in the history
…. docs: update the api about toFullDataUrl and other download related api. closes: #1657.
  • Loading branch information
Yanyan-Wang committed Jun 10, 2020
1 parent 807b60a commit ba97fa7
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#### 3.5.3
- feat: focusItem with animation;
- feat: generate the image url of the full graph by graph.toFullDataUrl;
- fix: graph dispears after being dragged out of the canvas and back;
- fix: the graph cannot be dragged back if it is already out of the view;
- fix: size and radius of the linkPoints problem;
Expand Down
54 changes: 50 additions & 4 deletions docs/api/Graph.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -1748,7 +1748,7 @@ graph.set('nodeIdList', [1, 3, 5]);



### downloadFullImage(name, imageConfig)
### downloadFullImage(name, type, imageConfig)

Export the whole graph as an image, whatever (a part of) the graph is out of the screen.

Expand All @@ -1757,6 +1757,7 @@ Export the whole graph as an image, whatever (a part of) the graph is out of the
| Name | Type | Required | Description |
| ---- | ------ | -------- | ---------- |
| name | String | false | The name of the image. 'graph' by default. |
| type | `'image/png'` / `'image/jpeg'` / `'image/webp'` / `'image/bmp'` | false | The type of the image. When the `renderer` of the graph is `'canvas'`(default), `type` takes effect. When the `renderer` is `'svg'`, `toFullDataURL` will export a svg file |
| imageConfig | Object | false | The configuration for the exported image, detials are shown below |

where the `imageConfig` is the configuration for exported image:
Expand Down Expand Up @@ -1792,15 +1793,15 @@ Export the canvas as an image.
graph.downloadImage();
```

### toDataURL()
### toDataURL(type, backgroundColor)

Generate url of a image of the canvas.
Generate url of the image of the graph inside the view port.

**Parameters**

| Name | Type | Required | Description |
| ---- | ------ | -------- | ---------- |
| type | String | false | The type of the image, options: `'image/png'`, `'image/jpeg'` |
| type | `'image/png'` / `'image/jpeg'` / `'image/webp'` / `'image/bmp'` | false | The type of the image. When the `renderer` of the graph is `'canvas'`(default), `type` takes effect. When the `renderer` is `'svg'`, `toFullDataURL` will export a svg file |
| backgroundColor | String | false | The background color of the image. If it is not assigned, the background will be transparent. |

**Return**
Expand All @@ -1813,3 +1814,48 @@ Generate url of a image of the canvas.
```javascript
const dataURL = graph.toDataURL();
```



### toFullDataURL(callback, type, backgroundColor)

Generate url of the image of the whole graph including the part out of the view port.

**Parameters**

| Name | Type | Required | Description |
| ---- | ------ | -------- | ---------- |
| callback | Function | true | The callback function after finish generating the dataUrl of the full graph
Asynchronously |
| type | `'image/png'` / `'image/jpeg'` / `'image/webp'` / `'image/bmp'` | false | The type of the image. When the `renderer` of the graph is `'canvas'`(default), `type` takes effect. When the `renderer` is `'svg'`, `toFullDataURL` will export a svg file |
| imageConfig | Object | false | The configuration for the exported image, detials are shown below |

where the `imageConfig` is the configuration for exported image:

| Name | Type | Required | Description |
| ---- | ------ | -------- | ---------- |
| backgroundColor | String | false | The background color of the image. If it is not assigned, the background will be transparent. |
| padding | Number / Number[] | false | The top, right, bottom, right paddings of the exported image. When its type is number, the paddings around the graph are the same |


No return value, you can process the result in the callback function as shown below:


**Usage**

```javascript
graph.toFullDataUrl(
// The first parameter: callback, required
(res) => {
// ... something
console.log(res); // e.g. print the result
},
// The second and third parameter is not required
'image/jpeg',
imageConfig: {
backgroundColor: '#fff',
padding: 10
}

)
```
50 changes: 48 additions & 2 deletions docs/api/Graph.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -1733,7 +1733,7 @@ graph.set('nodeIdList', [1, 3, 5]);
```


### downloadFullImage(name, imageConfig)
### downloadFullImage(name, type, imageConfig)

将画布上的元素导出为图片。

Expand All @@ -1742,6 +1742,7 @@ graph.set('nodeIdList', [1, 3, 5]);
| 名称 | 类型 | 是否必选 | 描述 |
| ---- | ------ | -------- | ---------- |
| name | String | false | 图片的名称,不指定则为 'graph' |
| type | `'image/png'` / `'image/jpeg'` / `'image/webp'` / `'image/bmp'` | false | 图片的类型。图的 `renderer` 为默认的 `'canvas'` 时生效,图的 `renderer``'svg'` 时将导出 svg 文件 |
| imageConfig | Object | false | 图片的配置项,可选,具体字段见下方 |

其中,imageConfig 为导出图片的配置参数:
Expand Down Expand Up @@ -1770,6 +1771,7 @@ graph.downloadFullImage('tree-graph', {
| 名称 | 类型 | 是否必选 | 描述 |
| ---- | ------ | -------- | ---------- |
| name | String | false | 图片的名称,不指定则为 'graph' |
| type | `'image/png'` / `'image/jpeg'` / `'image/webp'` / `'image/bmp'` | false | 图片的类型。图的 `renderer` 为默认的 `'canvas'` 时生效,图的 `renderer``'svg'` 时将导出 svg 文件 |
| backgroundColor | String | false | 图片的背景色,可选,不传值时将导出透明背景的图片 |

**用法**
Expand All @@ -1778,6 +1780,50 @@ graph.downloadFullImage('tree-graph', {
graph.downloadImage();
```

### toFullDataURL(callback, type, imageConfig)

将画布上元素生成为图片的 URL。

**参数**

| 名称 | 类型 | 是否必选 | 描述 |
| ---- | ------ | -------- | ---------- |
| callback | Function | true | 异步生成 dataUrl 完成后的回调函数,在这里处理生成的 dataUrl 字符串 |
| type | `'image/png'` / `'image/jpeg'` / `'image/webp'` / `'image/bmp'` | false | 图片的类型。图的 `renderer` 为默认的 `'canvas'` 时生效,图的 `renderer``'svg'` 时将导出 svg 文件 |
| imageConfig | Object | false | 图片的配置项,可选,具体字段见下方 |


其中,imageConfig 为导出图片的配置参数:

| 名称 | 类型 | 是否必选 | 描述 |
| ---- | ------ | -------- | ---------- |
| backgroundColor | String | false | 图片的背景色,可选,不传值时将导出透明背景的图片 |
| padding | Number / Number[] | false | 导出图片的上左下右 padding 值。当 `padding` 为 number 类型时,四周 `padding` 相等 |


无返回值,生成的结果请在 callback 中处理。如下示例:


**用法**

```javascript
graph.toFullDataUrl(
// 第一个参数为 callback,必须
(res) => {
// ... something
console.log(res); // 打印出结果
},
// 后两个参数不是必须
'image/jpeg',
imageConfig: {
backgroundColor: '#fff',
padding: 10
}

)
```


### toDataURL(type, backgroundColor)

将画布上元素生成为图片的 URL。
Expand All @@ -1786,7 +1832,7 @@ graph.downloadImage();

| 名称 | 类型 | 是否必选 | 描述 |
| ---- | ------ | -------- | ---------- |
| type | String | false | 图片类型,可选值:`'image/png'``'image/jpeg'` |
| type | `'image/png'` / `'image/jpeg'` / `'image/webp'` / `'image/bmp'` | false | 图片的类型。图的 `renderer` 为默认的 `'canvas'` 时生效,图的 `renderer``'svg'` 时将导出 svg 文件 |
| backgroundColor | String | false | 图片的背景色,可选,不传值时将导出透明背景的图片 |

**返回值**
Expand Down
4 changes: 2 additions & 2 deletions gatsby-browser.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
window.g6 = require('./src/index.ts'); // import the source for debugging
// window.g6 = require('./dist/g6.min.js'); // import the package for webworker
// window.g6 = require('./src/index.ts'); // import the source for debugging
window.g6 = require('./dist/g6.min.js'); // import the package for webworker
window.insertCss = require('insert-css');
106 changes: 98 additions & 8 deletions src/graph/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ interface IGroupBBox {
[key: string]: BBox;
}

type dataUrlType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/bmp';

export interface PrivateGraphOption extends GraphOptions {
data: GraphData;

Expand Down Expand Up @@ -1872,10 +1874,12 @@ export default class Graph extends EventEmitter implements IGraph {
}

/**
* 返回图表的 dataUrl 用于生成图片
* 返回可见区域的图的 dataUrl,用于生成图片
* @param {String} type 图片类型,可选值:"image/png" | "image/jpeg" | "image/webp" | "image/bmp"
* @param {string} backgroundColor 图片背景色
* @return {string} 图片 dataURL
*/
public toDataURL(type?: string, backgroundColor?: string): string {
public toDataURL(type?: dataUrlType, backgroundColor?: string): string {
const canvas: GCanvas = this.get('canvas');
const renderer = canvas.getRenderer();
const canvasDom = canvas.get('el');
Expand Down Expand Up @@ -1916,11 +1920,93 @@ export default class Graph extends EventEmitter implements IGraph {
return dataURL;
}

/**
* 返回整个图(包括超出可见区域的部分)的 dataUrl,用于生成图片
* @param {Function} callback 异步生成 dataUrl 完成后的回调函数,在这里处理生成的 dataUrl 字符串
* @param {String} type 图片类型,可选值:"image/png" | "image/jpeg" | "image/webp" | "image/bmp"
* @param {Object} imageConfig 图片配置项,包括背景色和上下左右的 padding
*/
public toFullDataURL(callback: (res: string) => any, type?: dataUrlType, imageConfig?: { backgroundColor?: string, padding?: number | number[] }) {
const bbox = this.get('group').getCanvasBBox();
const height = bbox.height;
const width = bbox.width;
const renderer = this.get('renderer');
const vContainerDOM: HTMLDivElement = createDom('<id="virtual-image"></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 = clone(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');

let dataURL = '';
if (!type) type = 'image/png';

setTimeout(() => {
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;
}
}
callback && callback(dataURL);
}, 16);
}

/**
* 导出包含全图的图片
* @param {String} name 图片的名称
* @param {String} type 图片类型,可选值:"image/png" | "image/jpeg" | "image/webp" | "image/bmp"
* @param {Object} imageConfig 图片配置项,包括背景色和上下左右的 padding
*/
public downloadFullImage(name?: string, imageConfig?: { backgroundColor?: string, padding?: number | number[] }): void {
public downloadFullImage(name?: string, type?: dataUrlType, imageConfig?: { backgroundColor?: string, padding?: number | number[] }): void {

const bbox = this.get('group').getCanvasBBox();
const height = bbox.height;
const width = bbox.width;
Expand Down Expand Up @@ -1957,8 +2043,8 @@ export default class Graph extends EventEmitter implements IGraph {

const vCanvasEl = vCanvas.get('el');

if (!type) type = 'image/png';
setTimeout(() => {
const type = 'image/png';
let dataURL = '';
if (renderer === 'svg') {
const clone = vCanvasEl.cloneNode(true);
Expand Down Expand Up @@ -1989,8 +2075,9 @@ export default class Graph extends EventEmitter implements IGraph {
}
}


const link: HTMLAnchorElement = document.createElement('a');
const fileName: string = (name || 'graph') + (renderer === 'svg' ? '.svg' : '.png');
const fileName: string = (name || 'graph') + (renderer === 'svg' ? '.svg' : `.${type.split('/')[1]}`);

this.dataURLToImage(dataURL, renderer, link, fileName);

Expand All @@ -2003,8 +2090,10 @@ export default class Graph extends EventEmitter implements IGraph {
/**
* 画布导出图片,图片仅包含画布可见区域部分内容
* @param {String} name 图片的名称
* @param {String} type 图片类型,可选值:"image/png" | "image/jpeg" | "image/webp" | "image/bmp"
* @param {string} backgroundColor 图片背景色
*/
public downloadImage(name?: string, backgroundColor?: string): void {
public downloadImage(name?: string, type?: dataUrlType, backgroundColor?: string): void {
const self = this;

if (self.isAnimating()) {
Expand All @@ -2013,10 +2102,11 @@ export default class Graph extends EventEmitter implements IGraph {

const canvas = self.get('canvas');
const renderer = canvas.getRenderer();
const fileName: string = (name || 'graph') + (renderer === 'svg' ? '.svg' : '.png');
if (!type) type = 'image/png';
const fileName: string = (name || 'graph') + (renderer === 'svg' ? '.svg' : type.split('/')[1]);
const link: HTMLAnchorElement = document.createElement('a');
setTimeout(() => {
const dataURL = self.toDataURL('image/png', backgroundColor);
const dataURL = self.toDataURL(type, backgroundColor);
this.dataURLToImage(dataURL, renderer, link, fileName);

const e = document.createEvent('MouseEvents');
Expand Down

0 comments on commit ba97fa7

Please sign in to comment.