Files
smart-fin-chart/js/merge.js
T
2026-09-09 15:31:05 +08:00

58 lines
2.1 KiB
JavaScript

/**
* 图片纵向合成 —— 把多张图表 PNG 顺序拼接为一张竖版长图。
* 公众号文章在手机上以竖版窗口预览,横版单图显示过小,
* 两张上下拼接后(2400×~2800)接近满屏,阅读体验明显更好。
* 纯浏览器 Canvas API,无依赖。
*/
const DEFAULTS = { gap: 96, background: '#fff' }; // gap 为设备像素:@2x 导出下 96 = 视觉 48px
function loadImage(src) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = () => reject(new Error('图片解码失败'));
img.src = src;
});
}
/**
* 按顺序纵向拼接一组图片 dataURL,返回合成后的 canvas。
* 宽度取各图最大值;宽度不一致的图等比缩放对齐(正常流程导出的图宽度一致,不会触发缩放)。
*/
export async function mergeImages(sources, options = {}) {
const { gap, background } = { ...DEFAULTS, ...options };
if (!sources.length) throw new Error('没有可合并的图片');
const images = await Promise.all(sources.map(loadImage));
const width = Math.max(...images.map((img) => img.width));
const heights = images.map((img) => Math.round(img.height * width / img.width));
const height = heights.reduce((sum, h) => sum + h, 0) + gap * (images.length - 1);
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.fillStyle = background;
ctx.fillRect(0, 0, width, height);
let y = 0;
images.forEach((img, index) => {
ctx.drawImage(img, 0, y, width, heights[index]);
y += heights[index] + gap;
});
return canvas;
}
/** canvas → PNG Blob 触发下载(Blob URL 比超长 dataURL 下载更稳) */
export function downloadCanvas(canvas, filename) {
canvas.toBlob((blob) => {
const url = URL.createObjectURL(blob);
const anchor = document.createElement('a');
anchor.href = url;
anchor.download = filename.endsWith('.png') ? filename : `${filename}.png`;
anchor.click();
setTimeout(() => URL.revokeObjectURL(url), 10_000);
}, 'image/png');
}