@antv/g-image-exporter
TypeScript icon, indicating that this package has built-in type declarations

1.0.2 • Public • Published

g-plugin-image-exporter

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

exporter in 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;
},

export html

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

Readme

Keywords

Package Sidebar

Install

npm i @antv/g-image-exporter

Weekly Downloads

3

Version

1.0.2

License

MIT

Unpacked Size

870 kB

Total Files

12

Last publish

Collaborators

  • lvisei
  • yisi.wang
  • basketduck
  • biupiubiupiu
  • flash1
  • dreammy23
  • laixingui.lxg
  • zhangjunjie-loki
  • rainy25ghz
  • zeyuwang
  • yanxiong
  • susiwen8
  • freestyle21
  • soundquiet
  • elaine.q.10
  • sturuby
  • sakuya223
  • serializedowen
  • xdzhao
  • yangzhanmei
  • wjgogogo
  • leungwensen
  • dori
  • iaaron
  • yard
  • simaq
  • dxq613
  • intchous
  • susan_ann
  • jinke.li
  • lzxue
  • army8735
  • atool
  • baizn
  • dengfuping
  • neoddish
  • jeffy2012
  • zqlu
  • afc163
  • pomelo-nwu
  • kopiluwaky
  • ccnuzindex
  • panyuqi
  • bubkoo
  • zengyue
  • kasmine
  • boyu.zlj
  • l1ud0ngq1
  • newbyvector
  • winniexing
  • chenluli
  • kn9117
  • xdddst
  • semious2020
  • esora
  • nadia_liu
  • bbsqq
  • mxz96102
  • openwayne
  • pearmini
  • pddpd
  • yiqianyao
  • zhanba
  • cxxxxxn