import { WATER_COLORS, PAPER_SIZE } from '../../constants/colors'; import { WORDS } from '../../constants/words'; import TextDrawService from '../../service/textDrawService'; Page({ canvas: null as Canvas | null, ctx: null as RenderingContext | null, boxHeight: 0, boxWidth: 0, textDrawService: null as TextDrawService | null, data: { cardList: [] as CardList, showColorPopup: false, currentKey: 0, currentColor: '', showIntroductionPopup: false, showSelectWordPopup: false, // 选择文字弹窗 env: 'release', }, onLoad() { const hasShowIntroduction = wx.getStorageSync('hasShowIntroduction') || false; if (!hasShowIntroduction) { this.setData({ cardList: [ { color: '#FF0000', word: '涂' }, { color: '#00FF00', word: '鸦' }, { color: '#FF7F00', word: '丫' }, { color: '#00FFFF', word: '欢' }, { color: '#FFFF00', word: '迎' }, { color: '#8A2BE2', word: '您' }, ], showIntroductionPopup: true, env: getApp().globalData.env || 'release', }); } else { this.setData({ env: getApp().globalData.env || 'release', }); } }, onReady() { 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.boxHeight = boxHeight; this.boxWidth = boxWidth; this.initCanvas(boxWidth, boxHeight); } }) .exec(); }, initCanvas(boxWidth: number, boxHeight: number) { 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; // const rect = res[0]; this.textDrawService = new TextDrawService(canvas, ctx); // textDrawService.draw(); this.setData({ boxWidth, boxHeight }); this.drawCanvas(); } } }); }, /** 变更cardList 并更新canvas */ drawCanvas( updatedCardList?: Array<{ color: string; word: string }>, callback: () => void = () => { }, ) { if (updatedCardList) { this.setData({ cardList: updatedCardList }, () => { this.textDrawService?.draw(updatedCardList!); callback(); }); } else { updatedCardList = this.data.cardList; this.textDrawService?.draw(updatedCardList); } }, tapCard(e: WechatMiniprogram.TouchEvent) { const { url } = e.currentTarget.dataset; wx.navigateTo({ url }); }, onConfirmInput(e: WechatMiniprogram.Input) { const { cardList } = this.data; const { value } = e.detail; const characters = value.split(''); // 计算剩余空间 const remainingSlots = 6 - cardList.length; if (remainingSlots <= 0) { wx.showToast({ title: '最多只能添加6个字哦!', icon: 'none', duration: 2000, }); return; } // 准备颜色数组 const allColors = WATER_COLORS.basic12.map((color) => color.hex); const usedColors = cardList.map((item) => item.color); const usedWords = cardList.map((item) => item.word); const availableColors = allColors.filter( (color) => !usedColors.includes(color), ); const shuffledColors = [...availableColors].sort( () => Math.random() - 0.5, ); const newCharacters: string[] = []; let isBeyond = false; for (const char of characters) { if (newCharacters.length >= remainingSlots) { isBeyond = true; break; } if (!usedWords.includes(char) && !newCharacters.includes(char)) { newCharacters.push(char); } } if (isBeyond) { wx.showToast({ title: '最多只能添加6个字,多余的字为被添加哦!', icon: 'none', duration: 2000, }); } // 为新字符创建卡片 const newCards = newCharacters.map((char) => { // 获取字对应的颜色 const colorHex = this.getColorByWord(char); let color: string; if (colorHex && !usedColors.includes(colorHex)) { // 如果有对应颜色且未被使用,使用对应颜色 color = colorHex; } else { // 否则随机选择一个可用颜色 const randomIndex = Math.floor(Math.random() * shuffledColors.length); color = shuffledColors[randomIndex]; // 从可用颜色中移除已使用的颜色 shuffledColors.splice(randomIndex, 1); } return { word: char, color: color }; }); // 合并新旧卡片 const updatedCardList = [...cardList, ...newCards]; this.drawCanvas(updatedCardList); }, deleteWordCard(e: WechatMiniprogram.CustomEvent) { const { key, word } = e.detail; const { cardList } = this.data; const updatedCardList = cardList.filter((_, index) => index !== key); this.drawCanvas(updatedCardList, () => { wx.showToast({ title: `已删除 "${word}"`, icon: 'none', duration: 2000, }); }); }, /** 下载打印 */ exportToPrint() { if (this.canvas && this.data.cardList.length > 0) { wx.canvasToTempFilePath({ canvas: this.canvas, fileType: 'png', quality: 1, success: (res) => { wx.getImageInfo({ src: res.tempFilePath, success: (res) => console.log( 'getImageInfo image size :', res.width, res.height, ), // 应输出2480x3508 }); wx.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success: () => wx.showToast({ title: '保存成功' }), }); }, }); return; } }, onColorTap(e: WechatMiniprogram.CustomEvent) { const { key, word, color } = e.detail; this.setData({ showColorPopup: true, currentKey: key, currentColor: color, }); }, onCloseColorPopup() { this.setData({ showColorPopup: false, currentKey: 0, currentColor: '', }); }, onChangeColor(e: WechatMiniprogram.CustomEvent) { const { color } = e.detail; const { currentKey, cardList } = this.data; cardList[currentKey].color = color; this.setData( { showColorPopup: false, cardList, }, () => { this.drawCanvas(); }, ); }, onCloseIntroductionPopup() { this.setData({ showIntroductionPopup: false }); wx.setStorageSync('hasShowIntroduction', true); }, onShareAppMessage() { return { title: '涂鸦丫 - 涂色|识字|画画|打印', path: '/pages/index/index', }; }, onShareTimeline() { return { title: '涂鸦丫 - 涂色|识字|画画|打印', query: '/pages/index/index', }; }, clearCardList() { this.drawCanvas([]); }, // 随机生成 refreshCardList() { // 获取前4个分类的所有文字 const allWords = WORDS.slice(0, 2).reduce((acc, category) => { return acc.concat(category.words); }, [] as string[]); // 随机获取6个不重复的文字 const selectedWords: string[] = []; while (selectedWords.length < 6) { const randomWord = allWords[Math.floor(Math.random() * allWords.length)]; if (!selectedWords.includes(randomWord)) { selectedWords.push(randomWord); } } // 随机获取6个不重复的颜色 const colors = [...WATER_COLORS.basic12]; const selectedColors: string[] = []; while (selectedColors.length < 6) { const randomIndex = Math.floor(Math.random() * colors.length); const color = colors.splice(randomIndex, 1)[0]; selectedColors.push(color.hex); } // 组合文字和颜色 const cardList = selectedWords.map((word, index) => ({ color: selectedColors[index], word })); this.drawCanvas(cardList); }, openSelectWordPopup() { this.setData({ showSelectWordPopup: true, }); }, closeSelectWordPopup() { this.setData({ showSelectWordPopup: false, }); }, // 获取颜色字对应的16进制颜色值 getColorByWord(word: string): string | null { const colorMap: Record = { '红': '#FF0000', '蓝': '#0000FF', '绿': '#00FF00', '黄': '#FFFF00', '黑': '#000000', '白': '#FFFFFF', '紫': '#800080', '橙': '#FF7F00', '粉': '#FF69B4', '棕': '#A52A2A', '灰': '#808080' }; return colorMap[word] || null; }, onChangeWord(e: WechatMiniprogram.CustomEvent) { const selectedWords = e.detail.selectedWords as string[]; const colors = [...WATER_COLORS.basic12]; const cardList = selectedWords.map((word, index) => { const colorHex = this.getColorByWord(word); return { color: colorHex || colors[index].hex, word }; }); this.setData({ showSelectWordPopup: false }); this.drawCanvas(cardList); }, onDebugEntryTap() { wx.navigateTo({ url: '/pages/debug/debug', }); }, });