1.0.3 • Published 4 days ago

@antv/g-image-exporter v1.0.3

Weekly downloads
-
License
MIT
Repository
github
Last release
4 days ago

g-plugin-image-exporter

一些图表库提供了保存内容到图片的功能,下图来自 Highcharts

为此我们提供了 g-image-exporter,它支持选定画布区域,导出指定格式的 dataURL 或保存成图片等功能,示例。其中部分功能依赖 DOM API,对于非浏览器运行环境,请参考 画布的特殊运行平台适配。例如下载功能需要通过 document.createElement('a') 实现,非浏览器环境需要自行传入 document 对象。

配置项

创建时可以指定以下配置项,其中 canvas 为必填项,将画布传入:

import { ImageExporter } from '@antv/g-image-exporter';

const exporter = new ImageExporter({
    canvas, // 传入画布
    defaultFilename: 'my-default-filename',
});

defaultFilename

在调用 downloadImage 保存并下载图片时,如果没有指定文件名,将使用该配置项的值作为默认文件名。

API

toCanvas

该方法用以将指定区域的画布内容绘制到额外的 HTMLCanvasElement 中,随后可以根据需要进一步加工,例如添加背景色、水印等。

完整方法签名如下,该方法为异步

toCanvas(options: Partial<CanvasOptions> = {}): Promise<HTMLCanvasElement>;

interface CanvasOptions {
  clippingRegion: Rectangle;
  beforeDrawImage: (context: CanvasRenderingContext2D) => void;
  afterDrawImage: (context: CanvasRenderingContext2D) => void;
}

各配置项含义如下:

  • clippingRegion 画布裁剪区域,用矩形表示
  • beforeDrawImage 在绘制画布内容前调用,适合绘制背景颜色
  • afterDrawImage 在绘制画布内容后调用,适合绘制水印
  • ignoreElements 在导出 HTML 内容时,如何判断容器内一个 HTMLElement 是否被忽略

在该示例中,我们添加了背景色和水印,通过传入的 CanvasRenderingContext2D 可以调用 Canvas2D API 进行绘制:

import { Rectangle } from '@antv/g';

const canvas = await exporter.toCanvas({
    // 忽略 stats.js lil-gui 等在容器内添加的 DOM 元素
    ignoreElements: (element) => {
        return [gui.domElement, stats.dom].indexOf(element) > -1;
    },
    // 指定导出画布区域
    clippingRegion: new Rectangle(
        clippingRegionX,
        clippingRegionY,
        clippingRegionWidth,
        clippingRegionHeight,
    ),
    beforeDrawImage: (context) => {
        // 绘制背景色
        context.fillStyle = backgroundColor;
        context.fillRect(0, 0, clippingRegionWidth, clippingRegionHeight);
    },
    afterDrawImage: (context) => {
        // 绘制水印
        context.font = '24px Times New Roman';
        context.fillStyle = '#FFC82C';
        context.fillText('AntV', 20, 20);
    },
});

注意裁剪区域使用的是 Rectangle 而非 Rect 图形。它的构造函数中包含 x/y/width/height 四个参数。它相对于视口坐标系下,即对于一个 400 x 400 的画布,裁剪的最大宽高就是 400。

在导出 HTML 时,默认会导出容器内的全部 HTMLElement,但有时有些元素并不是我们想导出的,此时可以使用 ignoreElements: (element: Element): boolean; 方法进行过滤。例如该示例中容器内还有 stats.js 和 lil-gui 添加的 DOM 元素,我们并不希望导出,此时可以:

ignoreElements: (element) => {
    return [gui.domElement, stats.dom].indexOf(element) > -1;
},

toSVGDataURL

有时我们想导出矢量图。不同于 toCanvas 对于所有渲染器都支持,只有 g-svg 渲染器支持生成 SVG 类型的 dataURL,如果选择了其他渲染器,将返回 Promise<undefined>

方法签名如下:

toSVGDataURL(): Promise<string>;

内部使用 XMLSerializer 实现,将 SVGElement 序列化成 XML 字符串。

downloadImage

触发浏览器下载行为,可以将 导出的 dataURL 传入并指定保存的文件名。

完整方法签名如下:

downloadImage(options: DownloadImageOptions): void;

interface DownloadImageOptions {
  dataURL: string;
  name?: string;
}

在该示例中,点击按钮立即开始下载图片,如果选择了 image/png 格式,最终保存成 my-file.png 文件:

const canvas = await exporter.toCanvas();
const dataURL = canvas.toDataURL();

// 触发下载
exporter.downloadImage({
    dataURL,
    name: 'my-file',
});

下载行为是通过使用 document创建 HTMLAnchorElement 并触发它的默认点击行为实现的。

导出 dataURL

通过 toCanvas 我们得到了包含画布内容的 HTMLCanvasElement,使用其原生方法 toDataURL 就可以得到 dataURL:

const canvas = await exporter.toCanvas();
const dataURL = canvas.toDataURL(); // data:...

toDataURL 方法中可以指定图片格式,默认为 image/png,以及图片质量,详见参数

导出 ImageData

HTMLCanvasElement 同样提供了 getImageData 方法用于获取指定区域的像素数据:

const canvas = await exporter.toCanvas();
const imageData = canvas.getImageData(50, 50, 100, 100); // ImageData { width: 100, height: 100, data: Uint8ClampedArray[40000] }

导出 PDF

如果我们还想在前端根据图片生成 PDF,可以参考:https://github.com/parallax/jsPDF

注意事项

导出图片的物理尺寸

导出图片的物理尺寸已经包含了 resolution,即对于指定了宽高 400 x 400 的画布,如果当前环境的 devicePixelRatio 为 2,将生成 800 x 800 的图片。

可以导出 HTML 吗?

可以,如果画布中包含 HTML,目前不同的渲染器实现如下:

在该示例中,左上角 Tooltip 就是一个 HTML。

为何 toCanvas 为异步方法?

HTMLCanvasElement 的原生方法 toDataURL 的确是一个同步方法。

但由于 WebGL / Canvaskit 使用双缓冲机制,拥有绘制 Buffer 和展示 Buffer。好处是相比每一帧都拷贝绘制 Buffer 的内容到展示 Buffer,直接交换效率更高。因此在创建 WebGL 上下文时我们关闭了 preserveDrawingBuffer,但需要确保调用 toDataURL 时渲染没有被清除(调用 gl.clear()),这会导致该行为变成异步,等待下一次渲染 tick 时才能获取内容。

另外在导出 HTML 内容时,使用 html2canvas 提供的导出方法同样也是一个异步操作。

如何导出画布视口之外的图形?

我们提供的导出方法都只针对画布视口范围,即使是裁剪也是相对视口坐标系下。因此如果想导出视口之外的图形,可以使用相机 API 在不改变场景结构的前提下改变视口范围,例如通过 setZoom 进行缩放,让视口内容纳更多图形。

toDataURL polyfill

HTMLCanvasElement 的原生方法 toDataURL 有可能在某些古早浏览器上不支持,此时可以使用 polyfill: https://stackoverflow.com/a/47148969

1.0.3

4 days ago

1.0.2

16 days ago

1.0.1

1 month ago

1.0.0

2 months ago

0.7.24

2 months ago

0.7.23

2 months ago

0.7.22-next.20

2 months ago

0.7.22-next.18

2 months ago

0.7.22-next.19

2 months ago

0.7.22-next.17

2 months ago

0.7.22-next.16

2 months ago

0.7.22-next.15

2 months ago

0.7.22-next.14

2 months ago

0.7.22

3 months ago

0.7.22-next.13

3 months ago

0.7.22-next.11

3 months ago

0.7.22-next.12

3 months ago

0.7.22-next.10

3 months ago

0.7.22-next.9

3 months ago

0.7.22-next.8

3 months ago

0.7.22-next.7

4 months ago

0.7.22-next.1

4 months ago

0.7.22-next.2

4 months ago

0.7.22-next.3

4 months ago

0.7.22-next.4

4 months ago

0.7.22-next.6

4 months ago

0.7.22-next.0

4 months ago

0.7.21

4 months ago

0.7.20

5 months ago

0.7.19

6 months ago

0.7.18

6 months ago

0.7.17

6 months ago

0.7.16

6 months ago

0.7.2

10 months ago

0.7.4

10 months ago

0.7.3

10 months ago

0.7.11

9 months ago

0.7.10

9 months ago

0.7.13

8 months ago

0.7.12

9 months ago

0.7.6

10 months ago

0.7.5

10 months ago

0.7.8

9 months ago

0.7.7

10 months ago

0.7.15

7 months ago

0.7.14

7 months ago

0.7.1

11 months ago

0.7.0

11 months ago

0.6.0

11 months ago

0.6.0-beta.1

11 months ago

0.6.0-alpha.1

11 months ago

0.5.50

12 months ago

0.5.49

12 months ago

0.5.47

1 year ago

0.5.48

12 months ago

0.5.46

1 year ago

0.5.43

1 year ago

0.5.44

1 year ago

0.5.41

1 year ago

0.5.42

1 year ago

0.5.40

1 year ago

0.5.45

1 year ago

0.5.39

1 year ago

0.5.38

1 year ago

0.5.36

1 year ago

0.5.37

1 year ago

0.5.35

1 year ago

0.5.19

2 years ago

0.5.32

1 year ago

0.5.33

1 year ago

0.5.30

1 year ago

0.5.31

1 year ago

0.5.34

1 year ago

0.5.21

2 years ago

0.5.22

2 years ago

0.5.20

2 years ago

0.5.29

1 year ago

0.5.27

2 years ago

0.5.28

1 year ago

0.5.25

2 years ago

0.5.26

2 years ago

0.5.23

2 years ago

0.5.24

2 years ago

0.5.18

2 years ago

0.5.10

2 years ago

0.5.11

2 years ago

0.5.8

2 years ago

0.5.7

2 years ago

0.5.9

2 years ago

0.5.16

2 years ago

0.5.17

2 years ago

0.5.14

2 years ago

0.5.15

2 years ago

0.5.12

2 years ago

0.5.13

2 years ago

0.5.4

2 years ago

0.5.3

2 years ago

0.5.6

2 years ago

0.5.5

2 years ago

0.5.2

2 years ago

0.5.1

2 years ago

0.5.0

2 years ago

0.4.3

2 years ago

0.4.2

2 years ago

0.4.1

2 years ago

0.4.0

2 years ago

0.4.0-alpha.0

2 years ago

0.3.3

2 years ago

0.3.2

2 years ago

0.3.1

2 years ago

0.3.0

2 years ago

0.2.0

2 years ago

0.1.1

2 years ago

0.1.0

2 years ago

0.0.2

2 years ago