import WordDrawService from '../../service/wordDrawService'; import { checkAndSaveImage } from '../../utils/saveImage'; import { PAPER_SIZE } from '../../constants/colors'; import { getWordsSvgData } from '../../utils/getWordsSvgJson'; Page({ canvas: null as Canvas | null, ctx: null as RenderingContext | null, wordDrawService: null as WordDrawService | null, svgWords: {} as Record, data: { // 选中的汉字列表 words: [] as string[], showSelectWordPopup: false, showColorPopup: false, currentKey: 0, currentColor: '', boxWidth: 0, boxHeight: 0, }, onLoad() { this.loadSvgWords(); const hasShowIntroduction = wx.getStorageSync('hasShowIntroduction') || false; if (!hasShowIntroduction) { this.setData({ words: ['好', '好', '学', '习', '天', '天', '向', '上'] }) } }, async onReady() { await this.setCanvasBoxSize(); this.initCanvas() }, async loadSvgWords() { try { wx.showToast({ title: '加载字体中...', icon: 'loading' }); // 使用带缓存的SVG汉字数据获取函数 const svgWordsData = await getWordsSvgData(); this.svgWords = svgWordsData; wx.hideToast(); console.log('SVG汉字数据加载成功,共', Object.keys(this.svgWords).length, '个汉字'); const { words } = this.data as any; if (words && words.length > 0) { this.drawPracticeSheet().catch(console.error); } } catch (error) { console.error('加载SVG汉字数据失败:', error); wx.hideToast(); // 显示错误提示 wx.showModal({ title: '加载失败', content: '无法加载汉字数据,请检查网络连接后重试', showCancel: true, cancelText: '取消', confirmText: '重试', success: (res) => { if (res.confirm) { // 用户点击重试,重新加载 this.loadSvgWords(); } } }); } }, // 输入组件回调 onConfirmInput(e: any) { const value: string = (e && e.detail && e.detail.value) || ''; const text = (value || '').trim(); if (!text) return; if (!this.isChineseText(text)) { wx.showToast({ title: '请输入汉字', icon: 'none' }); return; } const { words } = this.data as any; // 1. 先检查原来已有的汉字是否超过11个 if (words.length >= 11) { wx.showToast({ title: '最多只能添加 11 个字哦!', icon: 'none', duration: 2000, }); return; } // 2. 解析新输入的汉字 const newChars = this.splitToSingleChars(text); if (newChars.length === 0) { wx.showToast({ title: '请输入有效汉字', icon: 'none' }); return; } // 3. 保留原有汉字,追加新汉字(去重处理) const existingWords = new Set(words); // 用于快速查找重复 const updatedWords: string[] = [...words]; // 保留原有汉字 let addedCount = 0; let skippedCount = 0; for (const char of newChars) { // 检查是否已达到11个字的限制 if (updatedWords.length >= 11) { break; } // 检查是否已存在(去重) if (existingWords.has(char)) { skippedCount++; continue; } // 添加新汉字 updatedWords.push(char); existingWords.add(char); addedCount++; } // 4. 更新数据并提示 this.setData({ words: updatedWords }, () => { this.drawPracticeSheet().catch(console.error); }); // 5. 显示添加结果提示 if (addedCount > 0) { let message = `成功添加 ${addedCount} 个汉字`; if (skippedCount > 0) { message += `,跳过 ${skippedCount} 个重复汉字`; } if (updatedWords.length >= 11) { message += ',已达到最大限制'; } wx.showToast({ title: message, icon: 'none', duration: 2000, }); } else if (skippedCount > 0) { wx.showToast({ title: `所有汉字都已存在,跳过 ${skippedCount} 个重复汉字`, icon: 'none', duration: 2000, }); } }, // 选择面板 openSelectWordPopup() { this.setData({ showSelectWordPopup: true }); }, closeSelectWordPopup() { this.setData({ showSelectWordPopup: false }); }, onChangeWord(e: any) { const selectedWords = e.detail.selectedWords as string[]; const newWords = [...this.data.words, ...selectedWords]; this.setData({ words: newWords, showSelectWordPopup: false }, () => this.drawPracticeSheet().catch(console.error)); }, // 删除 deleteWordCard(e: any) { const { key } = e.detail; const { words } = this.data as any; const next = words.filter((_: string, index: number) => index !== key); console.log("-nextnext-----:", next); this.setData({ words: next }, () => this.drawPracticeSheet().catch(console.error)); }, // 校验 & 分割 isChineseText(text: string): boolean { const chineseRegex = /^[\u4e00-\u9fff]+$/; return chineseRegex.test(text); }, splitToSingleChars(text: string): string[] { const chineseRegex = /[\u4e00-\u9fff]/g; const matches = text.match(chineseRegex); return matches || []; }, setCanvasBoxSize() { const query = wx.createSelectorQuery(); query .select('#canvasWrapper') .boundingClientRect((rect) => { if (rect) { const { width, height } = PAPER_SIZE['A4']; const boxWidth = rect.width; const boxHeight = boxWidth / (width / height); this.setData({ boxWidth, boxHeight }); } }) .exec(); }, initCanvas() { // 然后初始化canvas wx.createSelectorQuery() .select('#canvasContent') .fields({ node: true, size: true, }) .exec((res) => { if (res[0] && res[0].node) { const canvas = res[0].node; const ctx = canvas.getContext('2d'); if (ctx) { this.canvas = canvas; this.ctx = ctx; this.wordDrawService = new WordDrawService(canvas, ctx, { appName: '涂鸦丫小程序', appHint: '练字|识字|涂色|打印', title: '田字格 练 字 贴', subTitle: '按笔画临摹练习' }); this.drawPracticeSheet().catch(console.error); } } }); }, // 绘制练字贴 async drawPracticeSheet() { if (!this.canvas || !this.wordDrawService) { this.initCanvas(); } const { words } = this.data as any; // 构建汉字笔画数据 const wordsMap: Record | null = this.checkWords(words); await this.wordDrawService?.draw(wordsMap || {}); }, checkWords(words: string[]): Record | null { // 构建汉字笔画数据(已去重) const wordsMap: Record = {}; const supportedWords: string[] = []; // 按顺序处理每个汉字 words.forEach((word: string) => { if (this.svgWords[word]) { wordsMap[word] = this.svgWords[word]; supportedWords.push(word); } }); if (supportedWords.length === 0) { wx.showToast({ title: '暂不支持这些汉字', icon: 'none' }); return null; } const maxRow = 11, maxCol = 9; let rowIndex = 0; const characters = Object.keys(wordsMap); const newWorksMap: Record = {}; const boundaryWords: string[] = [] characters.forEach((char) => { const strokes = wordsMap[char] || []; const strokeCount = strokes.length; const totalCells = 1 + strokeCount + 2; const totalRows = Math.ceil(totalCells / maxCol); rowIndex += totalRows; if (rowIndex <= maxRow) { newWorksMap[char] = wordsMap[char]; } else { boundaryWords.push(char) } }); if (boundaryWords.length > 0) { wx.showToast({ title: `练字贴已超过一页,部分汉字未包含在本次生成结果中`, icon: 'none' }); } return newWorksMap; }, // 下载打印练字贴 exportToPrint() { const { words } = this.data as any; if (!this.canvas || words.length <= 0) { wx.showToast({ title: '请先生成练字贴', icon: 'none' }); return; } checkAndSaveImage(this.canvas); }, // 分享功能 onShareAppMessage() { return { title: '涂鸦丫-练字|识字|打印', path: '/pages/copyBook/index', }; }, onShareTimeline() { return { title: '涂鸦丫-练字|识字|打印', query: '/pages/copyBook/index', }; }, });