diff --git a/miniprogram/app.json b/miniprogram/app.json
index fe42e9c..57bacf7 100644
--- a/miniprogram/app.json
+++ b/miniprogram/app.json
@@ -1,5 +1,9 @@
{
- "pages": ["pages/index/index", "pages/debug/debug"],
+ "pages": [
+ "pages/index/index",
+ "pages/debug/debug",
+ "pages/shapePrint/index"
+ ],
"window": {},
"style": "v2",
"rendererOptions": {
@@ -18,5 +22,17 @@
"scope.writePhotosAlbum": {
"desc": "需要保存涂色卡到相册"
}
+ },
+ "tabBar": {
+ "list": [
+ {
+ "pagePath": "pages/index/index",
+ "text": "识字"
+ },
+ {
+ "pagePath": "pages/shapePrint/index",
+ "text": "图形"
+ }
+ ]
}
}
diff --git a/miniprogram/pages/demoIndex/index.ts b/miniprogram/pages/demoIndex/index.ts
index 87dfc38..96abb70 100644
--- a/miniprogram/pages/demoIndex/index.ts
+++ b/miniprogram/pages/demoIndex/index.ts
@@ -8,8 +8,8 @@ Page({
},
{
key: 1,
- title: '文本绘制2',
- url: '/demoPages/textPaint2/textPaint',
+ title: '图形绘制',
+ url: '/demoPages/shapePrint/index',
},
{
key: 2,
diff --git a/miniprogram/pages/shapePrint/index.js b/miniprogram/pages/shapePrint/index.js
new file mode 100644
index 0000000..d90d2e9
--- /dev/null
+++ b/miniprogram/pages/shapePrint/index.js
@@ -0,0 +1,208 @@
+// 引入形状数据
+import { shapes, colors } from './shapes';
+
+Page({
+ data: {
+ shapeCards: [],
+ columns: 3,
+ bgColor: '#FFFFFF',
+ generatedImage: null,
+ isGenerating: false,
+ backgrounds: [
+ { name: '纯白', value: '#FFFFFF', color: '#f2f2f2' },
+ { name: '米黄', value: '#FAF5E8', color: '#d4c5a0' },
+ { name: '淡灰', value: '#F5F5F5', color: '#cccccc' },
+ { name: '无背景', value: 'transparent', color: '#000000' },
+ ],
+ },
+
+ onLoad() {
+ // 初始化示例卡片
+ const initialCards = [
+ this.createShapeCard('square', '#FF5252'),
+ this.createShapeCard('diamond', '#69F0AE'),
+ this.createShapeCard('cylinder', '#448AFF'),
+ this.createShapeCard('cube', '#FFD740'),
+ this.createShapeCard('circle', '#E040FB'),
+ this.createShapeCard('sphere', '#FAF5E8'),
+ // this.createShapeCard('triangle', '#FF9800'),
+ ];
+ this.setData({ shapeCards: initialCards });
+ },
+
+ createShapeCard(shapeId, fillColor) {
+ const shape = shapes.find((s) => s.id === shapeId);
+ return {
+ shape: shapeId,
+ fillColor,
+ svgData: this.generateSvgData(shape.svg, fillColor),
+ name: shape.name,
+ };
+ },
+
+ // SVG Base64生成器
+ generateSvgData(svgContent, fillColor) {
+ const styledSvg = svgContent.replace(/var\(--fill-color\)/g, fillColor);
+ const base64 = wx.arrayBufferToBase64(
+ new TextEncoder().encode(styledSvg),
+ );
+ return `data:image/svg+xml;base64,${base64}`;
+ },
+
+ // 设置列数
+ setColumns(e) {
+ this.setData({
+ columns: e.detail.value,
+ });
+ },
+
+ // 设置背景颜色
+ setBackground(e) {
+ this.setData({
+ bgColor: e.detail.value,
+ });
+ },
+
+ // 生成拼接图片
+ async generateImage() {
+ this.setData({ isGenerating: true });
+
+ try {
+ // 计算布局和画布尺寸
+ const cardCount = this.data.shapeCards.length;
+ const cardsPerRow = this.data.columns;
+ const canvasWidth = 750; // 以rpx为单位的宽度设计
+ const cardSize = canvasWidth / cardsPerRow;
+ const rowCount = Math.ceil(cardCount / cardsPerRow);
+ const canvasHeight = cardSize * rowCount;
+
+ // 创建离屏Canvas
+ const offscreenCanvas = wx.createOffscreenCanvas({
+ type: '2d',
+ width: canvasWidth,
+ height: canvasHeight,
+ });
+
+ const ctx = offscreenCanvas.getContext('2d');
+
+ // 填充背景
+ if (this.data.bgColor !== 'transparent') {
+ ctx.fillStyle = this.data.bgColor;
+ ctx.fillRect(0, 0, canvasWidth, canvasHeight);
+ }
+
+ // 批量加载图片的Promise数组
+ const loadPromises = this.data.shapeCards.map((card) => {
+ return new Promise((resolve) => {
+ wx.getImageInfo({
+ src: card.svgData,
+ success: (res) => {
+ resolve({
+ path: res.path,
+ card,
+ });
+ },
+ fail: () => {
+ resolve(null);
+ },
+ });
+ });
+ });
+
+ // 等待所有图片加载完成
+ const images = await Promise.all(loadPromises);
+
+ // 绘制所有卡片
+ images.forEach((imgInfo, index) => {
+ if (!imgInfo) return;
+
+ const row = Math.floor(index / cardsPerRow);
+ const col = index % cardsPerRow;
+ const x = col * cardSize + cardSize / 2;
+ const y = row * cardSize + cardSize / 2;
+
+ // 保存当前绘制状态
+ ctx.save();
+
+ // 添加卡片投影效果
+ ctx.shadowColor = 'rgba(0, 0, 0, 0.2)';
+ ctx.shadowBlur = 8;
+ ctx.shadowOffsetX = 0;
+ ctx.shadowOffsetY = 3;
+
+ // 绘制卡片SVG
+ ctx.drawImage(
+ imgInfo.path,
+ x - (cardSize * 0.8) / 2,
+ y - (cardSize * 0.8) / 2,
+ cardSize * 0.8,
+ cardSize * 0.8,
+ );
+
+ // 恢复绘制状态
+ ctx.restore();
+ });
+
+ // 将Canvas转换为临时图片路径
+ wx.canvasToTempFilePath({
+ canvas: offscreenCanvas,
+ success: (res) => {
+ this.setData({
+ generatedImage: res.tempFilePath,
+ isGenerating: false,
+ });
+ },
+ fail: () => {
+ this.setData({ isGenerating: false });
+ wx.showToast({ title: '图片生成失败', icon: 'none' });
+ },
+ });
+ } catch (e) {
+ this.setData({ isGenerating: false });
+ console.error(e);
+ wx.showToast({ title: '生成出错,请重试', icon: 'none' });
+ }
+ },
+
+ // 保存到相册
+ saveToAlbum() {
+ if (!this.data.generatedImage) return;
+
+ wx.saveImageToPhotosAlbum({
+ filePath: this.data.generatedImage,
+ success: () => {
+ wx.showToast({ title: '保存成功', icon: 'success' });
+ },
+ fail: (err) => {
+ if (err.errMsg === 'saveImageToPhotosAlbum:fail auth deny') {
+ this.showAuthGuide();
+ } else {
+ wx.showToast({ title: '保存失败', icon: 'none' });
+ }
+ },
+ });
+ },
+
+ // 显示授权引导
+ showAuthGuide() {
+ wx.showModal({
+ title: '权限申请',
+ content: '需要相册访问权限才能保存图片,请开启权限',
+ success: (res) => {
+ if (res.confirm) {
+ wx.openSetting();
+ }
+ },
+ });
+ },
+
+ // 预览大图
+ previewFullImage() {
+ if (!this.data.generatedImage) return;
+
+ wx.previewImage({
+ current: this.data.generatedImage,
+ urls: [this.data.generatedImage],
+ });
+ },
+});
diff --git a/miniprogram/pages/shapePrint/index.json b/miniprogram/pages/shapePrint/index.json
new file mode 100644
index 0000000..b686e95
--- /dev/null
+++ b/miniprogram/pages/shapePrint/index.json
@@ -0,0 +1,7 @@
+{
+ "navigationBarTitleText": "图形绘制 示例",
+ "navigationBarBackgroundColor": "#d2e7d8",
+ "homeButton": true,
+ "backgroundColor": "#e8eddb",
+ "enablePullDownRefresh": false
+}
diff --git a/miniprogram/pages/shapePrint/index.less b/miniprogram/pages/shapePrint/index.less
new file mode 100644
index 0000000..3b5fa5d
--- /dev/null
+++ b/miniprogram/pages/shapePrint/index.less
@@ -0,0 +1,84 @@
+.container {
+ padding: 20rpx;
+ background-color: #f5f7fa;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+}
+
+.card-container {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-around;
+ padding: 20rpx;
+ background: white;
+ border-radius: 20rpx;
+ margin-bottom: 30rpx;
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
+}
+
+.shape-card {
+ width: 200rpx;
+ height: 200rpx;
+ margin: 15rpx;
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 16rpx;
+ background: white;
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
+}
+
+.shape-image {
+ width: 140rpx;
+ height: 140rpx;
+}
+
+.color-box {
+ position: absolute;
+ bottom: 10rpx;
+ right: 10rpx;
+ width: 30rpx;
+ height: 30rpx;
+ border-radius: 6rpx;
+ border: 1rpx solid #eee;
+}
+
+.control-panel {
+ display: flex;
+ flex-direction: column;
+ gap: 20rpx;
+ padding: 30rpx;
+ background: white;
+ border-radius: 20rpx;
+ margin-bottom: 30rpx;
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
+}
+
+.bg-picker {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 20rpx;
+ padding: 20rpx;
+ background: white;
+ border-radius: 20rpx;
+ margin-bottom: 30rpx;
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
+}
+
+.label {
+ font-weight: bold;
+ color: #333;
+}
+
+.preview-image {
+ width: 100%;
+ height: 600rpx;
+ background-color: white;
+ border-radius: 20rpx;
+ margin-top: 20rpx;
+ box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.1);
+ border: 1rpx solid #eee;
+}
\ No newline at end of file
diff --git a/miniprogram/pages/shapePrint/index.wxml b/miniprogram/pages/shapePrint/index.wxml
new file mode 100644
index 0000000..2bd8678
--- /dev/null
+++ b/miniprogram/pages/shapePrint/index.wxml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 布局列数: {{columns}}
+
+
+
+
+
+
+
+
+
+
+
+ 背景颜色:
+
+
+ {{item.name}}
+
+
+
+
diff --git a/miniprogram/pages/shapePrint/shapes.js b/miniprogram/pages/shapePrint/shapes.js
new file mode 100644
index 0000000..15e8cc1
--- /dev/null
+++ b/miniprogram/pages/shapePrint/shapes.js
@@ -0,0 +1,61 @@
+// shapes.js
+const shapes = [
+ {
+ id: 'square',
+ name: '正方形',
+ svg: ``,
+ },
+ {
+ id: 'diamond',
+ name: '菱形',
+ svg: ``,
+ },
+ {
+ id: 'cylinder',
+ name: '圆柱体',
+ svg: ``,
+ },
+ {
+ id: 'cube',
+ name: '立方体',
+ svg: ``,
+ },
+ {
+ id: 'circle',
+ name: '圆形',
+ svg: ``,
+ },
+ {
+ id: 'sphere',
+ name: '球体',
+ svg: ``,
+ },
+];
+
+// 颜色选项
+const colors = [
+ { name: '红色', value: '#ff5252' },
+ { name: '蓝色', value: '#448aff' },
+ { name: '绿色', value: '#69f0ae' },
+ { name: '黄色', value: '#ffd740' },
+ { name: '紫色', value: '#e040fb' },
+];
+
+export { shapes, colors };