/** * Canvas 平台适配器 * 封装微信小程序 Canvas API,为未来 Web 平台迁移做准备 */ export interface CanvasInitResult { canvas: WechatMiniprogram.Canvas; ctx: CanvasRenderingContext2D; width: number; height: number; } /** * 初始化 Canvas 节点 * @param selector Canvas 选择器 (如 '#canvasContent') * @param wrapperSelector 容器选择器 (如 '#canvasWrapper') * @param aspectRatio 宽高比 (width / height) */ export function initCanvas( selector: string, wrapperSelector: string, aspectRatio: number, ): Promise { return new Promise((resolve, reject) => { const query = wx.createSelectorQuery(); query .select(wrapperSelector) .boundingClientRect((rect) => { if (!rect) { reject(new Error('Canvas wrapper not found')); return; } const boxWidth = rect.width; const boxHeight = boxWidth / aspectRatio; wx.createSelectorQuery() .select(selector) .fields({ node: true, size: true }) .exec((res) => { if (!res[0]) { reject(new Error('Canvas node not found')); return; } const canvas = res[0].node; const ctx = canvas.getContext('2d'); const dpr = wx.getSystemInfoSync().pixelRatio; canvas.width = boxWidth * dpr; canvas.height = boxHeight * dpr; ctx.scale(dpr, dpr); resolve({ canvas, ctx, width: boxWidth, height: boxHeight }); }); }) .exec(); }); } /** * Canvas 导出为临时文件路径 */ export function canvasToTempFilePath( canvas: WechatMiniprogram.Canvas, options?: { quality?: number; fileType?: 'png' | 'jpg' }, ): Promise { return new Promise((resolve, reject) => { wx.canvasToTempFilePath({ canvas, fileType: options?.fileType || 'png', quality: options?.quality || 1, success: (res) => resolve(res.tempFilePath), fail: reject, }); }); } /** * 加载图片到 Canvas */ export function loadImage( canvas: WechatMiniprogram.Canvas, src: string, ): Promise { return new Promise((resolve, reject) => { const img = canvas.createImage(); img.onload = () => resolve(img); img.onerror = reject; img.src = src; }); }