@mogura/moguchart-plugin-export 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present Murakami Hiroyuki
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.ja.md ADDED
@@ -0,0 +1,76 @@
1
+ # @mogura/moguchart-plugin-export
2
+
3
+ [English](./README.md)
4
+
5
+ ガントチャートライブラリ `@mogura/moguchart-core` 用の PNG / PDF エクスポートプラグインです。
6
+ `html2canvas-pro` および `jspdf` を使用し、Shadow DOM や高解像度分割エクスポートに対応しています。
7
+
8
+ ## インストール
9
+
10
+ ```bash
11
+ pnpm add @mogura/moguchart-plugin-export
12
+ # または
13
+ npm install @mogura/moguchart-plugin-export
14
+ ```
15
+
16
+ ## 使い方
17
+
18
+ ### 1. プラグインとして登録して使う(推奨)
19
+
20
+ チャートインスタンスにプラグインを登録すると、`chart.exportImage()` メソッドが有効化されます。
21
+
22
+ ```typescript
23
+ import '@mogura/moguchart-core'
24
+ import { exportPlugin } from '@mogura/moguchart-plugin-export'
25
+
26
+ const chart = document.querySelector('gantt-chart')
27
+
28
+ // プラグインの登録
29
+ chart.use(exportPlugin())
30
+
31
+ // または option.plugins で宣言的に渡すことも可能
32
+ chart.option = {
33
+ calendar: { ... },
34
+ plugins: [exportPlugin()]
35
+ }
36
+
37
+ // PNG エクスポート
38
+ await chart.exportImage('png', {
39
+ filename: 'my-project-schedule',
40
+ download: true,
41
+ scale: 2
42
+ })
43
+
44
+ // PDF エクスポート
45
+ await chart.exportImage('pdf', {
46
+ filename: 'my-project-schedule',
47
+ download: true
48
+ })
49
+ ```
50
+
51
+ ### 2. スタンドアロン関数として呼ぶ(必要な時だけ遅延インポート)
52
+
53
+ エクスポートボタンがクリックされた時だけ動的インポート(Dynamic Import)することで、初期バンドルサイズを最小限に抑えられます。
54
+
55
+ ```typescript
56
+ async function handleExportPdf(chartElement) {
57
+ const { exportChart } = await import('@mogura/moguchart-plugin-export')
58
+ await exportChart(chartElement, 'pdf', {
59
+ filename: 'gantt-export',
60
+ download: true
61
+ })
62
+ }
63
+ ```
64
+
65
+ ## オプション (`ExportImageOptions`)
66
+
67
+ | オプション | 型 | デフォルト値 | 説明 |
68
+ | :--- | :--- | :--- | :--- |
69
+ | `filename` | `string` | `'gantt-chart'` | ダウンロード時のファイル名(拡張子なし) |
70
+ | `download` | `boolean` | `false` | `true` の場合、自動的にファイルダウンロードをトリガー |
71
+ | `scale` | `number` | `2` | PNG 出力時の解像度倍率 |
72
+ | `splitHeight` | `number` | 未指定 | 指定ピクセル数で縦に分割し、分割位置にカレンダーヘッダーを挿入 |
73
+
74
+ ## ライセンス
75
+
76
+ MIT
package/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # @mogura/moguchart-plugin-export
2
+
3
+ [日本語](./README.ja.md)
4
+
5
+ PNG and PDF export plugin for the `@mogura/moguchart-core` Gantt chart component.
6
+ Powered by `html2canvas-pro` and `jspdf`, supporting Shadow DOM rendering and high-resolution multi-page split exports.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ pnpm add @mogura/moguchart-plugin-export
12
+ # or
13
+ npm install @mogura/moguchart-plugin-export
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ### 1. Register as a Plugin (Recommended)
19
+
20
+ Register the plugin to your Gantt chart instance to enable the `chart.exportImage()` method.
21
+
22
+ ```typescript
23
+ import '@mogura/moguchart-core'
24
+ import { exportPlugin } from '@mogura/moguchart-plugin-export'
25
+
26
+ const chart = document.querySelector('gantt-chart')
27
+
28
+ // Register plugin via chart.use()
29
+ chart.use(exportPlugin())
30
+
31
+ // Or pass declaratively via option.plugins
32
+ chart.option = {
33
+ calendar: { ... },
34
+ plugins: [exportPlugin()]
35
+ }
36
+
37
+ // Export as PNG image
38
+ await chart.exportImage('png', {
39
+ filename: 'my-project-schedule',
40
+ download: true,
41
+ scale: 2
42
+ })
43
+
44
+ // Export as PDF document
45
+ await chart.exportImage('pdf', {
46
+ filename: 'my-project-schedule',
47
+ download: true
48
+ })
49
+ ```
50
+
51
+ ### 2. Standalone Function (Dynamic Import for Code Splitting)
52
+
53
+ Dynamically import the export function only when the user triggers an export, keeping the initial page bundle minimal.
54
+
55
+ ```typescript
56
+ async function handleExportPdf(chartElement) {
57
+ const { exportChart } = await import('@mogura/moguchart-plugin-export')
58
+ await exportChart(chartElement, 'pdf', {
59
+ filename: 'gantt-export',
60
+ download: true
61
+ })
62
+ }
63
+ ```
64
+
65
+ ## Options (`ExportImageOptions`)
66
+
67
+ | Option | Type | Default | Description |
68
+ | :--- | :--- | :--- | :--- |
69
+ | `filename` | `string` | `'gantt-chart'` | File name for downloaded file (without extension) |
70
+ | `download` | `boolean` | `false` | If `true`, automatically triggers browser file download |
71
+ | `scale` | `number` | `2` | Resolution multiplier for PNG rendering |
72
+ | `splitHeight` | `number` | `undefined` | Split height in pixels for vertical multi-page division with repeating calendar headers |
73
+
74
+ ## License
75
+
76
+ MIT
@@ -0,0 +1,18 @@
1
+ /**
2
+ * ガントチャートを PNG 画像または PDF としてエクスポートするユーティリティ。
3
+ */
4
+ import type { GanttChartElement } from '@mogura/moguchart-core';
5
+ export interface ExportImageOptions {
6
+ /** ダウンロード時のファイル名(拡張子なし)。省略時は 'gantt-chart' */
7
+ filename?: string;
8
+ /** true の場合、自動的にファイルダウンロードを開始する。デフォルト: false */
9
+ download?: boolean;
10
+ /** PNG 出力時のスケール倍率(高解像度化)。デフォルト: 2 */
11
+ scale?: number;
12
+ /** 画像を指定したピクセル数で縦に分割し、分割位置にカレンダー(ヘッダー)を挿入する。未指定時は分割しない */
13
+ splitHeight?: number;
14
+ }
15
+ /**
16
+ * html2canvas-pro を使用してエクスポートする(Shadow DOMネイティブ対応版)
17
+ */
18
+ export declare function exportGanttWithHtml2Canvas(chartElement: GanttChartElement, format?: 'png' | 'pdf', options?: ExportImageOptions): Promise<string | Blob>;
@@ -0,0 +1,26 @@
1
+ import type { GanttChartElement, GanttPlugin } from '@mogura/moguchart-core';
2
+ import { exportGanttWithHtml2Canvas, type ExportImageOptions } from './export';
3
+ export interface ExportPluginConfig {
4
+ defaultScale?: number;
5
+ defaultFilename?: string;
6
+ }
7
+ /**
8
+ * ガントチャートのエクスポート(PNG/PDF)プラグイン
9
+ */
10
+ export declare function exportPlugin(config?: ExportPluginConfig): GanttPlugin<ExportPluginConfig>;
11
+ /**
12
+ * クラス形式の ExportPlugin
13
+ */
14
+ export declare class ExportPlugin implements GanttPlugin<ExportPluginConfig> {
15
+ name: string;
16
+ version: string;
17
+ config?: ExportPluginConfig;
18
+ constructor(config?: ExportPluginConfig);
19
+ install(chart: GanttChartElement, options?: ExportPluginConfig): void | undefined;
20
+ }
21
+ /**
22
+ * スタンドアロン実行関数
23
+ */
24
+ export declare function exportChart(chart: GanttChartElement, format?: 'png' | 'pdf', options?: ExportImageOptions): Promise<string | Blob>;
25
+ export { exportGanttWithHtml2Canvas };
26
+ export type { ExportImageOptions };
@@ -0,0 +1,134 @@
1
+ import e from "html2canvas-pro";
2
+ import { jsPDF as t } from "jspdf";
3
+ import { getThemeColors as n } from "@mogura/moguchart-core";
4
+ //#region src/export.ts
5
+ function r(e, t) {
6
+ let n = document.createElement("a");
7
+ n.href = e, n.download = t, n.click();
8
+ }
9
+ async function i(i, a = "png", o = {}) {
10
+ let { filename: s = "gantt-chart", download: c = !1, scale: l = 2, splitHeight: u } = o, d = i.shadowRoot?.querySelector(".scroll-container"), f = d ? d.scrollWidth : i.scrollWidth, p = d ? d.scrollHeight : i.scrollHeight, m = d || i, h = n(i.theme, i.option?.customTheme).bg || "#ffffff", g = await e(m, {
11
+ backgroundColor: h,
12
+ scale: l,
13
+ width: f,
14
+ height: p,
15
+ windowWidth: f,
16
+ windowHeight: p,
17
+ scrollX: 0,
18
+ scrollY: 0,
19
+ x: 0,
20
+ y: 0,
21
+ logging: !1
22
+ });
23
+ if (u && p > u) {
24
+ let e = 50, t = i.shadowRoot?.querySelector("gantt-calendar");
25
+ t && t.offsetHeight > 0 ? e = t.offsetHeight : i.calendarHeight && (e = i.calendarHeight);
26
+ let n = g.height / p, r = p - e, a = u - e, o = [];
27
+ typeof i.getRowPositions == "function" && (o = i.getRowPositions().map((e) => e.bottom));
28
+ let s = [0], c = 0;
29
+ if (a > 0) for (; c < r;) {
30
+ let e = c + a;
31
+ if (e >= r) {
32
+ s.push(r);
33
+ break;
34
+ }
35
+ let t = -1;
36
+ for (let n = 0; n < o.length; n++) {
37
+ let r = o[n];
38
+ r > c && r <= e && (t = Math.max(t, r));
39
+ }
40
+ if (t === -1) for (let e = 0; e < o.length; e++) {
41
+ let n = o[e];
42
+ if (n > c) {
43
+ t = n;
44
+ break;
45
+ }
46
+ }
47
+ (t === -1 || t === c) && (t = e), s.push(t), c = t;
48
+ }
49
+ else s.push(r);
50
+ let l = s.length - 1;
51
+ if (l > 0) {
52
+ let t = Math.floor(e * n), r = g.width, i = 0, a = [];
53
+ for (let r = 0; r < l; r++) {
54
+ let o = s[r], c = s[r + 1], l = Math.round((e + o) * n), u = Math.round((e + c) * n), d = u - l;
55
+ a.push({
56
+ srcStart: l,
57
+ srcEnd: u,
58
+ destHeight: d
59
+ }), i += t + d;
60
+ }
61
+ let o = document.createElement("canvas");
62
+ o.width = r, o.height = i;
63
+ let c = o.getContext("2d");
64
+ if (c) {
65
+ let e = 0;
66
+ for (let n = 0; n < l; n++) {
67
+ c.drawImage(g, 0, 0, r, t, 0, e, r, t), e += t;
68
+ let i = a[n];
69
+ c.drawImage(g, 0, i.srcStart, r, i.destHeight, 0, e, r, i.destHeight), e += i.destHeight;
70
+ }
71
+ g = o, p = i / n;
72
+ } else console.warn("[export] Failed to get 2D context for new canvas. It might be too large.");
73
+ }
74
+ }
75
+ if (a === "pdf") {
76
+ let e = g.toDataURL("image/jpeg", .9), n = new t({
77
+ orientation: f > p ? "l" : "p",
78
+ unit: "px",
79
+ format: [f, p],
80
+ compress: !0
81
+ });
82
+ return n.addImage(e, "JPEG", 0, 0, f, p, void 0, "FAST"), c && n.save(`${s}.pdf`), n.output("blob");
83
+ }
84
+ {
85
+ let e = g.toDataURL("image/png");
86
+ return c && r(e, `${s}.png`), e;
87
+ }
88
+ }
89
+ //#endregion
90
+ //#region src/index.ts
91
+ function a(e) {
92
+ return {
93
+ name: "export",
94
+ version: "1.0.0",
95
+ install(t, n) {
96
+ let r = {
97
+ ...e,
98
+ ...n
99
+ };
100
+ t.exportImage = async (e = "png", n = {}) => {
101
+ let a = t._scrollContainer || t.shadowRoot?.querySelector(".scroll-container"), o = a ? a.scrollLeft : 0, s = a ? a.scrollTop : 0;
102
+ t.isExporting = !0, await t.updateComplete, await new Promise((e) => requestAnimationFrame(e));
103
+ try {
104
+ return await i(t, e, {
105
+ scale: r.defaultScale ?? 2,
106
+ filename: r.defaultFilename,
107
+ ...n
108
+ });
109
+ } finally {
110
+ t.isExporting = !1, await t.updateComplete, a && (a.scrollLeft = o, a.scrollTop = s);
111
+ }
112
+ };
113
+ }
114
+ };
115
+ }
116
+ var o = class {
117
+ constructor(e) {
118
+ this.name = "export", this.version = "1.0.0", this.config = e;
119
+ }
120
+ install(e, t) {
121
+ return a(this.config).install?.(e, t);
122
+ }
123
+ };
124
+ async function s(e, t = "png", n = {}) {
125
+ let r = e._scrollContainer || e.shadowRoot?.querySelector(".scroll-container"), a = r ? r.scrollLeft : 0, o = r ? r.scrollTop : 0;
126
+ e.isExporting = !0, await e.updateComplete, await new Promise((e) => requestAnimationFrame(e));
127
+ try {
128
+ return await i(e, t, n);
129
+ } finally {
130
+ e.isExporting = !1, await e.updateComplete, r && (r.scrollLeft = a, r.scrollTop = o);
131
+ }
132
+ }
133
+ //#endregion
134
+ export { o as ExportPlugin, s as exportChart, i as exportGanttWithHtml2Canvas, a as exportPlugin };
@@ -0,0 +1 @@
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("html2canvas-pro"),require("jspdf"),require("@mogura/moguchart-core")):typeof define==`function`&&define.amd?define([`exports`,`html2canvas-pro`,`jspdf`,`@mogura/moguchart-core`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.MoguchartPluginExport={},e.html2canvas,e.jsPDF,e.MoguchartCore))})(this,function(e,t,n,r){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var i=Object.create,a=Object.defineProperty,o=Object.getOwnPropertyDescriptor,s=Object.getOwnPropertyNames,c=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty,u=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=s(t),c=0,u=i.length,d;c<u;c++)d=i[c],!l.call(e,d)&&d!==n&&a(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=o(t,d))||r.enumerable});return e};t=((e,t,n)=>(n=e==null?{}:i(c(e)),u(t||!e||!e.__esModule||!l.call(e,`default`)?a(n,`default`,{value:e,enumerable:!0}):n,e)))(t,1);function d(e,t){let n=document.createElement(`a`);n.href=e,n.download=t,n.click()}async function f(e,i=`png`,a={}){let{filename:o=`gantt-chart`,download:s=!1,scale:c=2,splitHeight:l}=a,u=e.shadowRoot?.querySelector(`.scroll-container`),f=u?u.scrollWidth:e.scrollWidth,p=u?u.scrollHeight:e.scrollHeight,m=u||e,h=(0,r.getThemeColors)(e.theme,e.option?.customTheme).bg||`#ffffff`,g=await(0,t.default)(m,{backgroundColor:h,scale:c,width:f,height:p,windowWidth:f,windowHeight:p,scrollX:0,scrollY:0,x:0,y:0,logging:!1});if(l&&p>l){let t=50,n=e.shadowRoot?.querySelector(`gantt-calendar`);n&&n.offsetHeight>0?t=n.offsetHeight:e.calendarHeight&&(t=e.calendarHeight);let r=g.height/p,i=p-t,a=l-t,o=[];typeof e.getRowPositions==`function`&&(o=e.getRowPositions().map(e=>e.bottom));let s=[0],c=0;if(a>0)for(;c<i;){let e=c+a;if(e>=i){s.push(i);break}let t=-1;for(let n=0;n<o.length;n++){let r=o[n];r>c&&r<=e&&(t=Math.max(t,r))}if(t===-1)for(let e=0;e<o.length;e++){let n=o[e];if(n>c){t=n;break}}(t===-1||t===c)&&(t=e),s.push(t),c=t}else s.push(i);let u=s.length-1;if(u>0){let e=Math.floor(t*r),n=g.width,i=0,a=[];for(let n=0;n<u;n++){let o=s[n],c=s[n+1],l=Math.round((t+o)*r),u=Math.round((t+c)*r),d=u-l;a.push({srcStart:l,srcEnd:u,destHeight:d}),i+=e+d}let o=document.createElement(`canvas`);o.width=n,o.height=i;let c=o.getContext(`2d`);if(c){let t=0;for(let r=0;r<u;r++){c.drawImage(g,0,0,n,e,0,t,n,e),t+=e;let i=a[r];c.drawImage(g,0,i.srcStart,n,i.destHeight,0,t,n,i.destHeight),t+=i.destHeight}g=o,p=i/r}else console.warn(`[export] Failed to get 2D context for new canvas. It might be too large.`)}}if(i===`pdf`){let e=g.toDataURL(`image/jpeg`,.9),t=new n.jsPDF({orientation:f>p?`l`:`p`,unit:`px`,format:[f,p],compress:!0});return t.addImage(e,`JPEG`,0,0,f,p,void 0,`FAST`),s&&t.save(`${o}.pdf`),t.output(`blob`)}{let e=g.toDataURL(`image/png`);return s&&d(e,`${o}.png`),e}}function p(e){return{name:`export`,version:`1.0.0`,install(t,n){let r={...e,...n};t.exportImage=async(e=`png`,n={})=>{let i=t._scrollContainer||t.shadowRoot?.querySelector(`.scroll-container`),a=i?i.scrollLeft:0,o=i?i.scrollTop:0;t.isExporting=!0,await t.updateComplete,await new Promise(e=>requestAnimationFrame(e));try{return await f(t,e,{scale:r.defaultScale??2,filename:r.defaultFilename,...n})}finally{t.isExporting=!1,await t.updateComplete,i&&(i.scrollLeft=a,i.scrollTop=o)}}}}}var m=class{constructor(e){this.name=`export`,this.version=`1.0.0`,this.config=e}install(e,t){return p(this.config).install?.(e,t)}};async function h(e,t=`png`,n={}){let r=e._scrollContainer||e.shadowRoot?.querySelector(`.scroll-container`),i=r?r.scrollLeft:0,a=r?r.scrollTop:0;e.isExporting=!0,await e.updateComplete,await new Promise(e=>requestAnimationFrame(e));try{return await f(e,t,n)}finally{e.isExporting=!1,await e.updateComplete,r&&(r.scrollLeft=i,r.scrollTop=a)}}e.ExportPlugin=m,e.exportChart=h,e.exportGanttWithHtml2Canvas=f,e.exportPlugin=p});
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@mogura/moguchart-plugin-export",
3
+ "type": "module",
4
+ "version": "1.1.0",
5
+ "description": "PNG and PDF export plugin for @mogura/moguchart-core",
6
+ "license": "MIT",
7
+ "author": "Murakami Hiroyuki",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/hiro-murakami/moguchart-core.git",
11
+ "directory": "packages/plugin-export"
12
+ },
13
+ "homepage": "https://github.com/hiro-murakami/moguchart-core",
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "keywords": [
18
+ "gantt",
19
+ "moguchart",
20
+ "export",
21
+ "pdf",
22
+ "png",
23
+ "html2canvas",
24
+ "jspdf"
25
+ ],
26
+ "files": [
27
+ "dist",
28
+ "README.md",
29
+ "README.ja.md"
30
+ ],
31
+ "main": "./dist/moguchart-plugin-export.umd.js",
32
+ "module": "./dist/moguchart-plugin-export.mjs",
33
+ "types": "./dist/index.d.ts",
34
+ "exports": {
35
+ ".": {
36
+ "types": "./dist/index.d.ts",
37
+ "import": "./dist/moguchart-plugin-export.mjs",
38
+ "require": "./dist/moguchart-plugin-export.umd.js"
39
+ }
40
+ },
41
+ "peerDependencies": {
42
+ "lit": "^3.0.0",
43
+ "@mogura/moguchart-core": "1.1.0"
44
+ },
45
+ "dependencies": {
46
+ "html2canvas-pro": "^2.0.2",
47
+ "jspdf": "^4.2.1"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^24.12.0",
51
+ "jsdom": "^27.4.0",
52
+ "lit": "^3.3.2",
53
+ "typescript": "^5.9.3",
54
+ "vite": "^8.0.0",
55
+ "vitest": "^4.0.16",
56
+ "@mogura/moguchart-core": "1.1.0"
57
+ },
58
+ "scripts": {
59
+ "build": "vite build && pnpm exec tsc -p tsconfig.build.json",
60
+ "test": "vitest",
61
+ "test:run": "vitest run"
62
+ }
63
+ }