feat:练字贴生成
This commit is contained in:
@@ -10,28 +10,29 @@ Page({
|
||||
|
||||
data: {
|
||||
// 选中的汉字列表
|
||||
words: ['赢', '张', '政'] as string[],
|
||||
words: [] as string[],
|
||||
showSelectWordPopup: false,
|
||||
showColorPopup: false,
|
||||
currentKey: 0,
|
||||
currentColor: '',
|
||||
|
||||
// 田字格配置
|
||||
// rows: 10,
|
||||
// cols: 12,
|
||||
// rowsArray: [] as number[],
|
||||
// colsArray: [] as number[],
|
||||
boxWidth: 0,
|
||||
boxHeight: 0,
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
// this.initGrid();
|
||||
this.loadSvgWords();
|
||||
const hasShowIntroduction =
|
||||
wx.getStorageSync('hasShowIntroduction') || false;
|
||||
if (!hasShowIntroduction) {
|
||||
this.setData({
|
||||
words: ['好', '好', '学', '习', '天', '天', '向', '上']
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onReady() {
|
||||
this.setCanvasBoxSize();
|
||||
async onReady() {
|
||||
await this.setCanvasBoxSize();
|
||||
this.initCanvas()
|
||||
},
|
||||
|
||||
loadSvgWords() {
|
||||
@@ -44,9 +45,7 @@ Page({
|
||||
wx.showToast({ title: '加载中...', icon: 'loading' });
|
||||
const parsedData = JSON.parse(res.data as string);
|
||||
this.svgWords = parsedData;
|
||||
console.log('this.svgWords.length----:', Object.keys(this.svgWords).length)
|
||||
wx.hideToast();
|
||||
console.log('SVG words loaded successfully');
|
||||
const { words } = this.data as any;
|
||||
if (words && words.length > 0) {
|
||||
this.drawPracticeSheet().catch(console.error);
|
||||
@@ -73,16 +72,75 @@ Page({
|
||||
return;
|
||||
}
|
||||
|
||||
const chars = this.splitToSingleChars(text);
|
||||
const { words } = this.data as any;
|
||||
const exists = new Set(words);
|
||||
const newWords = [...words];
|
||||
chars.forEach((ch) => {
|
||||
if (!exists.has(ch)) {
|
||||
newWords.push(ch);
|
||||
|
||||
// 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);
|
||||
});
|
||||
this.setData({ words: newWords }, () => 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,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 选择面板
|
||||
@@ -98,11 +156,12 @@ Page({
|
||||
this.setData({ words: newWords, showSelectWordPopup: false }, () => this.drawPracticeSheet().catch(console.error));
|
||||
},
|
||||
|
||||
// 删除与颜色
|
||||
// 删除
|
||||
deleteWordCard(e: any) {
|
||||
const { word } = e.detail;
|
||||
const { key } = e.detail;
|
||||
const { words } = this.data as any;
|
||||
const next = words.filter((w: string) => w !== word);
|
||||
const next = words.filter((_: string, index: number) => index !== key);
|
||||
console.log("-nextnext-----:", next);
|
||||
this.setData({ words: next }, () => this.drawPracticeSheet().catch(console.error));
|
||||
},
|
||||
|
||||
@@ -117,16 +176,6 @@ Page({
|
||||
return matches || [];
|
||||
},
|
||||
|
||||
// 田字格
|
||||
/* initGrid() {
|
||||
const { rows, cols } = this.data as any;
|
||||
const rowsArray = Array.from({ length: rows }, (_, i) => i);
|
||||
const colsArray = Array.from({ length: cols }, (_, i) => i);
|
||||
console.log('rowsArray----:', rowsArray)
|
||||
console.log('colsArray----:', colsArray)
|
||||
this.setData({ rowsArray, colsArray });
|
||||
}, */
|
||||
|
||||
setCanvasBoxSize() {
|
||||
const query = wx.createSelectorQuery();
|
||||
query
|
||||
@@ -158,7 +207,7 @@ Page({
|
||||
this.ctx = ctx;
|
||||
this.wordDrawService = new WordDrawService(canvas, ctx, {
|
||||
appName: '涂鸦丫小程序',
|
||||
appHint: '练字|识字|打印',
|
||||
appHint: '练字|识字|涂色|打印',
|
||||
title: '田字格 练 字 贴',
|
||||
subTitle: '按笔画临摹练习'
|
||||
});
|
||||
@@ -174,26 +223,53 @@ Page({
|
||||
this.initCanvas();
|
||||
}
|
||||
const { words } = this.data as any;
|
||||
if (!words || words.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建汉字笔画数据
|
||||
const wordsMap: Record<string, string[]> | null = this.checkWords(words);
|
||||
await this.wordDrawService?.draw(wordsMap || {});
|
||||
},
|
||||
|
||||
checkWords(words: string[]): Record<string, string[]> | null {
|
||||
// 构建汉字笔画数据(已去重)
|
||||
const wordsMap: Record<string, string[]> = {};
|
||||
console.log('this.svgWords----:', this.svgWords)
|
||||
const supportedWords: string[] = [];
|
||||
|
||||
// 按顺序处理每个汉字
|
||||
words.forEach((word: string) => {
|
||||
if (this.svgWords[word]) {
|
||||
wordsMap[word] = this.svgWords[word];
|
||||
supportedWords.push(word);
|
||||
}
|
||||
});
|
||||
if (Object.keys(wordsMap).length === 0) {
|
||||
|
||||
if (supportedWords.length === 0) {
|
||||
wx.showToast({ title: '暂不支持这些汉字', icon: 'none' });
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
await this.wordDrawService?.draw(wordsMap);
|
||||
},
|
||||
const maxRow = 11, maxCol = 9;
|
||||
let rowIndex = 0;
|
||||
const characters = Object.keys(wordsMap);
|
||||
const newWorksMap: Record<string, string[]> = {};
|
||||
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;
|
||||
|
||||
@@ -39,12 +39,10 @@
|
||||
<text class="wrapper-title">预览练字田字格</text>
|
||||
<view id="canvasWrapper" class="canvas-wrapper">
|
||||
<canvas
|
||||
wx:if="{{words}}"
|
||||
type="2d"
|
||||
id="canvasContent"
|
||||
class="canvas-content"
|
||||
style="width:{{boxWidth}}px;height:{{boxHeight}}px" />
|
||||
<view wx:else class="empty-tip">请选择或输入汉字后生成田字格</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -75,6 +73,7 @@
|
||||
<word-picker
|
||||
show="{{showSelectWordPopup}}"
|
||||
selectedWords="{{words}}"
|
||||
max="11"
|
||||
bind:onClose="closeSelectWordPopup"
|
||||
bind:onChange="onChangeWord" />
|
||||
|
||||
|
||||
@@ -71,9 +71,6 @@ Page({
|
||||
const boxWidth = rect.width;
|
||||
const boxHeight = boxWidth / (width / height);
|
||||
|
||||
console.log('boxWidth----:', boxWidth)
|
||||
console.log('boxHeight----:', boxHeight)
|
||||
|
||||
// 然后初始化canvas
|
||||
wx.createSelectorQuery()
|
||||
.select('#canvasContent')
|
||||
@@ -182,7 +179,7 @@ Page({
|
||||
}
|
||||
if (isBeyond) {
|
||||
wx.showToast({
|
||||
title: '最多只能添加6个字,多余的字为被添加哦!',
|
||||
title: '最多只能添加6个字,多余的字未被添加哦!',
|
||||
icon: 'none',
|
||||
duration: 2000,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user