diff --git a/miniprogram/demoPages/shapePrint/index.js b/miniprogram/demoPages/shapePrint/index.js
index 318f4f8..69af751 100644
--- a/miniprogram/demoPages/shapePrint/index.js
+++ b/miniprogram/demoPages/shapePrint/index.js
@@ -1,18 +1,17 @@
// 引入形状和颜色数据
import { shapes, colors } from './shapes';
+import { WATER_COLORS } from '../../constants/colors';
Page({
data: {
// 可选择的形状列表
availableShapes: shapes,
- // 可选择的颜色列表
- availableColors: colors,
// 已选择的形状列表
selectedShapes: [],
- // 当前选中的形状类型
- currentShapeType: 'circle',
- // 当前选中的颜色
- currentColor: '#FF4444',
+ // 基础12色
+ basic12Colors: WATER_COLORS.basic12,
+ // 已使用的颜色索引(确保不重复)
+ usedColorIndexes: [],
// 生成的图片
generatedImage: null,
// 是否正在生成
@@ -24,178 +23,580 @@ Page({
{ name: '淡灰', value: '#F5F5F5' },
],
bgColor: '#FFFFFF',
+ // 弹窗控制
+ showShapeSelector: false,
+ showColorPicker: false,
+ // 当前编辑的形状索引
+ currentEditingIndex: -1,
+ currentEditingColor: '',
+ // 临时选择的形状ID列表(弹窗中的选择状态)
+ tempSelectedShapeIds: [],
},
onLoad() {
console.log('形状绘制页面加载完成');
+ // 初始化临时选择列表
+ this.setData({
+ tempSelectedShapeIds: this.data.selectedShapes.map(
+ (shape) => shape.id,
+ ),
+ });
},
- // 选择形状类型
- selectShape(e) {
+ // 打开形状选择器
+ openShapeSelector() {
+ this.setData({
+ showShapeSelector: true,
+ // 将当前已选择的形状ID设置到临时列表中
+ tempSelectedShapeIds: this.data.selectedShapes.map(
+ (shape) => shape.shapeId,
+ ),
+ });
+ },
+
+ // 关闭形状选择器
+ closeShapeSelector() {
+ this.setData({
+ showShapeSelector: false,
+ });
+ },
+
+ // 切换形状选择状态
+ toggleShape(e) {
const shapeId = e.currentTarget.dataset.shapeId;
- this.setData({
- currentShapeType: shapeId,
+ const { tempSelectedShapeIds } = this.data;
+
+ if (tempSelectedShapeIds.includes(shapeId)) {
+ // 取消选择
+ const newTempSelected = tempSelectedShapeIds.filter(
+ (id) => id !== shapeId,
+ );
+ this.setData({
+ tempSelectedShapeIds: newTempSelected,
+ });
+ } else {
+ // 添加选择(最多6个)
+ if (tempSelectedShapeIds.length < 6) {
+ this.setData({
+ tempSelectedShapeIds: [...tempSelectedShapeIds, shapeId],
+ });
+ } else {
+ wx.showToast({
+ title: '最多只能选择6个形状',
+ icon: 'none',
+ duration: 2000,
+ });
+ }
+ }
+ },
+
+ // 确认形状选择
+ confirmShapeSelection() {
+ const { tempSelectedShapeIds, availableShapes, selectedShapes } =
+ this.data;
+
+ // 构建新的选择列表
+ const newSelectedShapes = [];
+ const usedColorIndexes = [];
+
+ tempSelectedShapeIds.forEach((shapeId, index) => {
+ const shape = availableShapes.find((s) => s.id === shapeId);
+ if (shape) {
+ // 查找是否已存在该形状
+ const existingShape = selectedShapes.find(
+ (s) => s.shapeId === shapeId,
+ );
+ if (existingShape) {
+ // 保持原有颜色
+ newSelectedShapes.push(existingShape);
+ const colorIndex = this.data.basic12Colors.findIndex(
+ (c) => c.hex === existingShape.fillColor,
+ );
+ if (colorIndex !== -1) {
+ usedColorIndexes.push(colorIndex);
+ }
+ } else {
+ // 新形状,分配随机颜色
+ const randomColor =
+ this.getRandomUnusedColor(usedColorIndexes);
+ newSelectedShapes.push({
+ id: Date.now() + index,
+ shapeId: shape.id,
+ name: shape.name,
+ fillColor: randomColor.hex,
+ colorName: randomColor.name,
+ drawFunction: shape.drawFunction,
+ });
+ }
+ }
+ });
+
+ this.setData(
+ {
+ selectedShapes: newSelectedShapes,
+ usedColorIndexes,
+ showShapeSelector: false,
+ },
+ () => {
+ // 自动生成新的打印纸
+ if (newSelectedShapes.length > 0) {
+ this.generateImage();
+ }
+ },
+ );
+
+ wx.showToast({
+ title: `已选择${newSelectedShapes.length}个形状`,
+ icon: 'success',
+ duration: 1500,
});
},
- // 选择颜色
- selectColor(e) {
- const color = e.currentTarget.dataset.color;
- this.setData({
- currentColor: color,
+ // 获取随机未使用的颜色
+ getRandomUnusedColor(usedIndexes) {
+ const { basic12Colors } = this.data;
+ const availableIndexes = [];
+
+ for (let i = 0; i < basic12Colors.length; i++) {
+ if (!usedIndexes.includes(i)) {
+ availableIndexes.push(i);
+ }
+ }
+
+ if (availableIndexes.length === 0) {
+ // 如果所有颜色都被使用,则重新开始
+ const randomIndex = Math.floor(
+ Math.random() * basic12Colors.length,
+ );
+ usedIndexes.push(randomIndex);
+ return basic12Colors[randomIndex];
+ }
+
+ const randomIndex =
+ availableIndexes[
+ Math.floor(Math.random() * availableIndexes.length)
+ ];
+ usedIndexes.push(randomIndex);
+ return basic12Colors[randomIndex];
+ },
+
+ // 删除形状
+ deleteShape(e) {
+ const index = parseInt(e.currentTarget.dataset.index);
+ const selectedShapes = [...this.data.selectedShapes];
+ const deletedShape = selectedShapes[index];
+
+ // 释放颜色
+ const colorIndex = this.data.basic12Colors.findIndex(
+ (c) => c.hex === deletedShape.fillColor,
+ );
+ const usedColorIndexes = this.data.usedColorIndexes.filter(
+ (i) => i !== colorIndex,
+ );
+
+ selectedShapes.splice(index, 1);
+
+ this.setData(
+ {
+ selectedShapes,
+ usedColorIndexes,
+ },
+ () => {
+ // 如果还有形状,自动重新生成
+ if (selectedShapes.length > 0) {
+ this.generateImage();
+ } else {
+ // 清空生成的图片
+ this.setData({
+ generatedImage: null,
+ });
+ }
+ },
+ );
+
+ wx.showToast({
+ title: '已删除形状',
+ icon: 'success',
+ duration: 1000,
});
},
- // 添加形状到选中列表
- addShape() {
- const { currentShapeType, currentColor, selectedShapes } = this.data;
- const shape = shapes.find((s) => s.id === currentShapeType);
+ // 打开颜色选择器
+ openColorPicker(e) {
+ const index = parseInt(e.currentTarget.dataset.index);
+ const shape = this.data.selectedShapes[index];
- if (shape) {
- const newShape = {
- id: Date.now(),
- type: shape.type,
- name: shape.name,
- color: currentColor,
- shapeId: currentShapeType,
- drawFunction: shape.drawFunction,
+ this.setData({
+ showColorPicker: true,
+ currentEditingIndex: index,
+ currentEditingColor: shape.fillColor,
+ });
+ },
+
+ // 关闭颜色选择器
+ closeColorPicker() {
+ this.setData({
+ showColorPicker: false,
+ currentEditingIndex: -1,
+ currentEditingColor: '',
+ });
+ },
+
+ // 颜色改变事件
+ onColorChange(e) {
+ const { color } = e.detail;
+ const { currentEditingIndex, selectedShapes, basic12Colors } =
+ this.data;
+
+ if (currentEditingIndex >= 0) {
+ const newSelectedShapes = [...selectedShapes];
+ const colorInfo = basic12Colors.find((c) => c.hex === color) ||
+ WATER_COLORS.extended24.find((c) => c.hex === color) || {
+ name: '自定义色',
+ hex: color,
+ };
+
+ newSelectedShapes[currentEditingIndex] = {
+ ...newSelectedShapes[currentEditingIndex],
+ fillColor: color,
+ colorName: colorInfo.name,
};
- this.setData({
- selectedShapes: [...selectedShapes, newShape],
- });
+ this.setData(
+ {
+ selectedShapes: newSelectedShapes,
+ showColorPicker: false,
+ currentEditingIndex: -1,
+ },
+ () => {
+ // 自动重新生成
+ this.generateImage();
+ },
+ );
wx.showToast({
- title: `添加了${shape.name}`,
+ title: '颜色已更新',
icon: 'success',
duration: 1000,
});
}
},
- // 删除选中的形状
- removeShape(e) {
- const index = e.currentTarget.dataset.index;
- const selectedShapes = [...this.data.selectedShapes];
- selectedShapes.splice(index, 1);
- this.setData({
- selectedShapes,
- });
- },
-
- // 清空所有形状
- clearShapes() {
- this.setData({
- selectedShapes: [],
- });
- },
-
// 设置背景颜色
setBackground(e) {
- this.setData({
- bgColor: e.detail.value,
+ this.setData(
+ {
+ bgColor: e.detail.value,
+ },
+ () => {
+ // 如果有形状,自动重新生成
+ if (this.data.selectedShapes.length > 0) {
+ this.generateImage();
+ }
+ },
+ );
+ },
+
+ // 生成练习页图片
+ async generateImage() {
+ if (this.data.selectedShapes.length === 0) {
+ wx.showToast({
+ title: '请先选择形状',
+ icon: 'none',
+ });
+ return;
+ }
+
+ this.setData({ isGenerating: true });
+
+ try {
+ const canvas = await this.getCanvas();
+ const ctx = canvas.getContext('2d');
+
+ // A4纸张尺寸 (595x842 像素,72 DPI)
+ const width = 595;
+ const height = 842;
+
+ // 设置画布尺寸
+ canvas.width = width;
+ canvas.height = height;
+
+ // 设置背景
+ ctx.fillStyle = this.data.bgColor;
+ ctx.fillRect(0, 0, width, height);
+
+ // 绘制标题
+ this.drawTitle(ctx, width);
+
+ // 绘制有颜色的示例部分(上半部)
+ this.drawColoredExamples(ctx, width, height);
+
+ // 绘制分隔线
+ this.drawDivider(ctx, width, height);
+
+ // 绘制练习区域(下半部,无颜色)
+ this.drawPracticeArea(ctx, width, height);
+
+ // 导出图片
+ const tempFilePath = canvas.toTempFilePathSync({
+ fileType: 'png',
+ quality: 1,
+ });
+
+ this.setData({
+ generatedImage: tempFilePath,
+ isGenerating: false,
+ });
+
+ wx.showToast({
+ title: '生成完成',
+ icon: 'success',
+ });
+ } catch (error) {
+ console.error('生成图片失败:', error);
+ this.setData({ isGenerating: false });
+ wx.showToast({
+ title: '生成失败,请重试',
+ icon: 'none',
+ });
+ }
+ },
+
+ // 获取Canvas实例
+ getCanvas() {
+ return new Promise((resolve) => {
+ const query = wx.createSelectorQuery().in(this);
+ query
+ .select('#mainCanvas')
+ .fields({ node: true, size: true })
+ .exec((res) => {
+ const canvas = res[0].node;
+ resolve(canvas);
+ });
});
},
- // 创建形状的SVG预览
- createShapePreview(shape) {
- const svgContent = `
-
- `;
+ // 绘制标题
+ drawTitle(ctx, width) {
+ ctx.save();
+ ctx.fillStyle = '#333';
+ ctx.font = 'bold 24px Arial';
+ ctx.textAlign = 'center';
+ ctx.fillText('形状涂色练习', width / 2, 40);
- const base64 = wx.arrayBufferToBase64(
- new TextEncoder().encode(svgContent),
- );
- return `data:image/svg+xml;base64,${base64}`;
+ ctx.font = '16px Arial';
+ ctx.fillText('请为下面的形状涂上颜色', width / 2, 70);
+ ctx.restore();
},
- // 绘制各种形状的函数
- drawCircle(ctx, x, y, size, color, filled = true) {
+ // 绘制有颜色的示例
+ drawColoredExamples(ctx, width, height) {
+ const { selectedShapes } = this.data;
+ const startY = 100;
+ const shapeSize = 80;
+ const cols = 3;
+ const spacing = width / (cols + 1);
+
+ selectedShapes.forEach((shape, index) => {
+ const row = Math.floor(index / cols);
+ const col = index % cols;
+ const x = (col + 1) * spacing;
+ const y = startY + row * (shapeSize + 60);
+
+ // 绘制形状
+ this.drawShapeOnCanvas(ctx, shape, x, y, shapeSize, true);
+
+ // 绘制形状名称
+ ctx.save();
+ ctx.fillStyle = '#333';
+ ctx.font = '14px Arial';
+ ctx.textAlign = 'center';
+ ctx.fillText(shape.name, x, y + shapeSize / 2 + 25);
+ ctx.restore();
+ });
+ },
+
+ // 绘制分隔线
+ drawDivider(ctx, width, height) {
+ const y = height / 2;
ctx.save();
- if (filled) {
- ctx.fillStyle = color;
+ ctx.strokeStyle = '#ccc';
+ ctx.lineWidth = 2;
+ ctx.setLineDash([10, 5]);
+ ctx.beginPath();
+ ctx.moveTo(50, y);
+ ctx.lineTo(width - 50, y);
+ ctx.stroke();
+
+ // 分隔线文字
+ ctx.fillStyle = '#666';
+ ctx.font = '14px Arial';
+ ctx.textAlign = 'center';
+ ctx.fillText('练习区域(请涂色)', width / 2, y + 20);
+ ctx.restore();
+ },
+
+ // 绘制练习区域
+ drawPracticeArea(ctx, width, height) {
+ const { selectedShapes } = this.data;
+ const startY = height / 2 + 60;
+ const shapeSize = 80;
+ const cols = 3;
+ const spacing = width / (cols + 1);
+
+ selectedShapes.forEach((shape, index) => {
+ const row = Math.floor(index / cols);
+ const col = index % cols;
+ const x = (col + 1) * spacing;
+ const y = startY + row * (shapeSize + 60);
+
+ // 绘制形状(无填充色,仅轮廓)
+ this.drawShapeOnCanvas(ctx, shape, x, y, shapeSize, false);
+
+ // 绘制形状名称
+ ctx.save();
+ ctx.fillStyle = '#333';
+ ctx.font = '14px Arial';
+ ctx.textAlign = 'center';
+ ctx.fillText(shape.name, x, y + shapeSize / 2 + 25);
+ ctx.restore();
+ });
+ },
+
+ // 在Canvas上绘制形状
+ drawShapeOnCanvas(ctx, shape, x, y, size, filled) {
+ const color = filled ? shape.fillColor : 'transparent';
+
+ switch (shape.drawFunction) {
+ case 'drawCircle':
+ this.drawCircle(ctx, x, y, size, color, '#333', filled);
+ break;
+ case 'drawSquare':
+ this.drawSquare(ctx, x, y, size, color, '#333', filled);
+ break;
+ case 'drawRectangle':
+ this.drawRectangle(ctx, x, y, size, color, '#333', filled);
+ break;
+ case 'drawTriangle':
+ this.drawTriangle(ctx, x, y, size, color, '#333', filled);
+ break;
+ case 'drawOval':
+ this.drawOval(ctx, x, y, size, color, '#333', filled);
+ break;
+ case 'drawDiamond':
+ this.drawDiamond(ctx, x, y, size, color, '#333', filled);
+ break;
+ case 'drawStar':
+ this.drawStar(ctx, x, y, size, color, '#333', filled);
+ break;
+ case 'drawHeart':
+ this.drawHeart(ctx, x, y, size, color, '#333', filled);
+ break;
+ case 'drawHexagon':
+ this.drawHexagon(ctx, x, y, size, color, '#333', filled);
+ break;
+ case 'drawPentagon':
+ this.drawPentagon(ctx, x, y, size, color, '#333', filled);
+ break;
+ case 'drawSemicircle':
+ this.drawSemicircle(ctx, x, y, size, color, '#333', filled);
+ break;
+ case 'drawTrapezoid':
+ this.drawTrapezoid(ctx, x, y, size, color, '#333', filled);
+ break;
}
- ctx.strokeStyle = '#333';
- ctx.lineWidth = 3;
+ },
+
+ // 绘制各种形状的函数(更新参数以支持边框色)
+ drawCircle(ctx, x, y, size, fillColor, borderColor, filled = true) {
+ ctx.save();
ctx.beginPath();
ctx.arc(x, y, size * 0.4, 0, Math.PI * 2);
- if (filled) ctx.fill();
+
+ if (filled && fillColor !== 'transparent') {
+ ctx.fillStyle = fillColor;
+ ctx.fill();
+ }
+
+ ctx.strokeStyle = borderColor;
+ ctx.lineWidth = 3;
ctx.stroke();
ctx.restore();
},
- drawSquare(ctx, x, y, size, color, filled = true) {
+ drawSquare(ctx, x, y, size, fillColor, borderColor, filled = true) {
ctx.save();
- if (filled) {
- ctx.fillStyle = color;
- }
- ctx.strokeStyle = '#333';
- ctx.lineWidth = 3;
const squareSize = size * 0.8;
const startX = x - squareSize / 2;
const startY = y - squareSize / 2;
- if (filled) ctx.fillRect(startX, startY, squareSize, squareSize);
+
+ if (filled && fillColor !== 'transparent') {
+ ctx.fillStyle = fillColor;
+ ctx.fillRect(startX, startY, squareSize, squareSize);
+ }
+
+ ctx.strokeStyle = borderColor;
+ ctx.lineWidth = 3;
ctx.strokeRect(startX, startY, squareSize, squareSize);
ctx.restore();
},
- drawRectangle(ctx, x, y, size, color, filled = true) {
+ drawRectangle(ctx, x, y, size, fillColor, borderColor, filled = true) {
ctx.save();
- if (filled) {
- ctx.fillStyle = color;
- }
- ctx.strokeStyle = '#333';
- ctx.lineWidth = 3;
const rectWidth = size * 0.9;
const rectHeight = size * 0.6;
const startX = x - rectWidth / 2;
const startY = y - rectHeight / 2;
- if (filled) ctx.fillRect(startX, startY, rectWidth, rectHeight);
+
+ if (filled && fillColor !== 'transparent') {
+ ctx.fillStyle = fillColor;
+ ctx.fillRect(startX, startY, rectWidth, rectHeight);
+ }
+
+ ctx.strokeStyle = borderColor;
+ ctx.lineWidth = 3;
ctx.strokeRect(startX, startY, rectWidth, rectHeight);
ctx.restore();
},
- drawTriangle(ctx, x, y, size, color, filled = true) {
+ drawTriangle(ctx, x, y, size, fillColor, borderColor, filled = true) {
ctx.save();
- if (filled) {
- ctx.fillStyle = color;
- }
- ctx.strokeStyle = '#333';
- ctx.lineWidth = 3;
const triangleSize = size * 0.8;
ctx.beginPath();
ctx.moveTo(x, y - triangleSize / 2);
ctx.lineTo(x - triangleSize / 2, y + triangleSize / 2);
ctx.lineTo(x + triangleSize / 2, y + triangleSize / 2);
ctx.closePath();
- if (filled) ctx.fill();
+
+ if (filled && fillColor !== 'transparent') {
+ ctx.fillStyle = fillColor;
+ ctx.fill();
+ }
+
+ ctx.strokeStyle = borderColor;
+ ctx.lineWidth = 3;
ctx.stroke();
ctx.restore();
},
- drawOval(ctx, x, y, size, color, filled = true) {
+ drawOval(ctx, x, y, size, fillColor, borderColor, filled = true) {
ctx.save();
- if (filled) {
- ctx.fillStyle = color;
- }
- ctx.strokeStyle = '#333';
- ctx.lineWidth = 3;
ctx.beginPath();
ctx.ellipse(x, y, size * 0.45, size * 0.3, 0, 0, Math.PI * 2);
- if (filled) ctx.fill();
+
+ if (filled && fillColor !== 'transparent') {
+ ctx.fillStyle = fillColor;
+ ctx.fill();
+ }
+
+ ctx.strokeStyle = borderColor;
+ ctx.lineWidth = 3;
ctx.stroke();
ctx.restore();
},
- drawDiamond(ctx, x, y, size, color, filled = true) {
+ drawDiamond(ctx, x, y, size, fillColor, borderColor, filled = true) {
ctx.save();
- if (filled) {
- ctx.fillStyle = color;
- }
- ctx.strokeStyle = '#333';
- ctx.lineWidth = 3;
const diamondSize = size * 0.4;
ctx.beginPath();
ctx.moveTo(x, y - diamondSize);
@@ -203,18 +604,20 @@ Page({
ctx.lineTo(x, y + diamondSize);
ctx.lineTo(x - diamondSize, y);
ctx.closePath();
- if (filled) ctx.fill();
+
+ if (filled && fillColor !== 'transparent') {
+ ctx.fillStyle = fillColor;
+ ctx.fill();
+ }
+
+ ctx.strokeStyle = borderColor;
+ ctx.lineWidth = 3;
ctx.stroke();
ctx.restore();
},
- drawStar(ctx, x, y, size, color, filled = true) {
+ drawStar(ctx, x, y, size, fillColor, borderColor, filled = true) {
ctx.save();
- if (filled) {
- ctx.fillStyle = color;
- }
- ctx.strokeStyle = '#333';
- ctx.lineWidth = 3;
const outerRadius = size * 0.4;
const innerRadius = size * 0.2;
ctx.beginPath();
@@ -227,18 +630,20 @@ Page({
else ctx.lineTo(pointX, pointY);
}
ctx.closePath();
- if (filled) ctx.fill();
+
+ if (filled && fillColor !== 'transparent') {
+ ctx.fillStyle = fillColor;
+ ctx.fill();
+ }
+
+ ctx.strokeStyle = borderColor;
+ ctx.lineWidth = 3;
ctx.stroke();
ctx.restore();
},
- drawHeart(ctx, x, y, size, color, filled = true) {
+ drawHeart(ctx, x, y, size, fillColor, borderColor, filled = true) {
ctx.save();
- if (filled) {
- ctx.fillStyle = color;
- }
- ctx.strokeStyle = '#333';
- ctx.lineWidth = 3;
const heartSize = size * 0.4;
ctx.beginPath();
ctx.moveTo(x, y + heartSize * 0.3);
@@ -258,18 +663,20 @@ Page({
x,
y + heartSize * 0.3,
);
- if (filled) ctx.fill();
+
+ if (filled && fillColor !== 'transparent') {
+ ctx.fillStyle = fillColor;
+ ctx.fill();
+ }
+
+ ctx.strokeStyle = borderColor;
+ ctx.lineWidth = 3;
ctx.stroke();
ctx.restore();
},
- drawHexagon(ctx, x, y, size, color, filled = true) {
+ drawHexagon(ctx, x, y, size, fillColor, borderColor, filled = true) {
ctx.save();
- if (filled) {
- ctx.fillStyle = color;
- }
- ctx.strokeStyle = '#333';
- ctx.lineWidth = 3;
const radius = size * 0.4;
ctx.beginPath();
for (let i = 0; i < 6; i++) {
@@ -280,18 +687,20 @@ Page({
else ctx.lineTo(pointX, pointY);
}
ctx.closePath();
- if (filled) ctx.fill();
+
+ if (filled && fillColor !== 'transparent') {
+ ctx.fillStyle = fillColor;
+ ctx.fill();
+ }
+
+ ctx.strokeStyle = borderColor;
+ ctx.lineWidth = 3;
ctx.stroke();
ctx.restore();
},
- drawPentagon(ctx, x, y, size, color, filled = true) {
+ drawPentagon(ctx, x, y, size, fillColor, borderColor, filled = true) {
ctx.save();
- if (filled) {
- ctx.fillStyle = color;
- }
- ctx.strokeStyle = '#333';
- ctx.lineWidth = 3;
const radius = size * 0.4;
ctx.beginPath();
for (let i = 0; i < 5; i++) {
@@ -302,34 +711,38 @@ Page({
else ctx.lineTo(pointX, pointY);
}
ctx.closePath();
- if (filled) ctx.fill();
+
+ if (filled && fillColor !== 'transparent') {
+ ctx.fillStyle = fillColor;
+ ctx.fill();
+ }
+
+ ctx.strokeStyle = borderColor;
+ ctx.lineWidth = 3;
ctx.stroke();
ctx.restore();
},
- drawSemicircle(ctx, x, y, size, color, filled = true) {
+ drawSemicircle(ctx, x, y, size, fillColor, borderColor, filled = true) {
ctx.save();
- if (filled) {
- ctx.fillStyle = color;
- }
- ctx.strokeStyle = '#333';
- ctx.lineWidth = 3;
const radius = size * 0.4;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI);
ctx.closePath();
- if (filled) ctx.fill();
+
+ if (filled && fillColor !== 'transparent') {
+ ctx.fillStyle = fillColor;
+ ctx.fill();
+ }
+
+ ctx.strokeStyle = borderColor;
+ ctx.lineWidth = 3;
ctx.stroke();
ctx.restore();
},
- drawTrapezoid(ctx, x, y, size, color, filled = true) {
+ drawTrapezoid(ctx, x, y, size, fillColor, borderColor, filled = true) {
ctx.save();
- if (filled) {
- ctx.fillStyle = color;
- }
- ctx.strokeStyle = '#333';
- ctx.lineWidth = 3;
const trapezoidSize = size * 0.4;
ctx.beginPath();
ctx.moveTo(x - trapezoidSize * 0.6, y - trapezoidSize * 0.5);
@@ -337,245 +750,23 @@ Page({
ctx.lineTo(x + trapezoidSize, y + trapezoidSize * 0.5);
ctx.lineTo(x - trapezoidSize, y + trapezoidSize * 0.5);
ctx.closePath();
- if (filled) ctx.fill();
+
+ if (filled && fillColor !== 'transparent') {
+ ctx.fillStyle = fillColor;
+ ctx.fill();
+ }
+
+ ctx.strokeStyle = borderColor;
+ ctx.lineWidth = 3;
ctx.stroke();
ctx.restore();
},
- // 绘制形状的通用方法
- drawShape(ctx, shape, x, y, size, filled = true) {
- const color = filled ? shape.color : 'transparent';
-
- switch (shape.drawFunction) {
- case 'drawCircle':
- this.drawCircle(ctx, x, y, size, color, filled);
- break;
- case 'drawSquare':
- this.drawSquare(ctx, x, y, size, color, filled);
- break;
- case 'drawRectangle':
- this.drawRectangle(ctx, x, y, size, color, filled);
- break;
- case 'drawTriangle':
- this.drawTriangle(ctx, x, y, size, color, filled);
- break;
- case 'drawOval':
- this.drawOval(ctx, x, y, size, color, filled);
- break;
- case 'drawDiamond':
- this.drawDiamond(ctx, x, y, size, color, filled);
- break;
- case 'drawStar':
- this.drawStar(ctx, x, y, size, color, filled);
- break;
- case 'drawHeart':
- this.drawHeart(ctx, x, y, size, color, filled);
- break;
- case 'drawHexagon':
- this.drawHexagon(ctx, x, y, size, color, filled);
- break;
- case 'drawPentagon':
- this.drawPentagon(ctx, x, y, size, color, filled);
- break;
- case 'drawSemicircle':
- this.drawSemicircle(ctx, x, y, size, color, filled);
- break;
- case 'drawTrapezoid':
- this.drawTrapezoid(ctx, x, y, size, color, filled);
- break;
- }
- },
-
- // 生成A4纸张大小的图片
- async generateImage() {
- if (this.data.selectedShapes.length === 0) {
- wx.showToast({
- title: '请先添加形状',
- icon: 'none',
- });
- return;
- }
-
- this.setData({ isGenerating: true });
-
- try {
- const query = wx.createSelectorQuery().in(this);
-
- query
- .select('#mainCanvas')
- .fields({ node: true, size: true })
- .exec((res) => {
- if (!res[0] || !res[0].node) {
- this.setData({ isGenerating: false });
- wx.showToast({
- title: 'Canvas 获取失败',
- icon: 'none',
- });
- return;
- }
-
- const canvas = res[0].node;
- const ctx = canvas.getContext('2d');
-
- // A4纸张尺寸 (595x842 点,按照72DPI)
- const dpr = wx.getSystemInfoSync().pixelRatio;
- const a4Width = 595;
- const a4Height = 842;
-
- canvas.width = a4Width * dpr;
- canvas.height = a4Height * dpr;
- ctx.scale(dpr, dpr);
-
- // 清空画布并设置背景
- ctx.clearRect(0, 0, a4Width, a4Height);
- ctx.fillStyle = this.data.bgColor;
- ctx.fillRect(0, 0, a4Width, a4Height);
-
- // 绘制标题
- this.drawTitle(ctx, a4Width);
-
- // 绘制上半部分:带颜色的形状示例
- this.drawUpperSection(ctx, a4Width, a4Height);
-
- // 绘制分割线
- this.drawDividerLine(ctx, a4Width, a4Height * 0.45);
-
- // 绘制下半部分:无颜色的练习区域
- this.drawLowerSection(ctx, a4Width, a4Height);
-
- // 导出图片
- wx.canvasToTempFilePath({
- canvas: canvas,
- success: (res) => {
- this.setData({
- generatedImage: res.tempFilePath,
- isGenerating: false,
- });
- wx.showToast({
- title: '图片生成成功',
- icon: 'success',
- });
- },
- fail: (err) => {
- console.error('导出图片失败:', err);
- this.setData({ isGenerating: false });
- wx.showToast({
- title: '图片生成失败',
- icon: 'none',
- });
- },
- });
- });
- } catch (error) {
- console.error('生成图片出错:', error);
- this.setData({ isGenerating: false });
- wx.showToast({
- title: '生成出错,请重试',
- icon: 'none',
- });
- }
- },
-
- // 绘制标题
- drawTitle(ctx, canvasWidth) {
- ctx.save();
- ctx.fillStyle = '#333';
- ctx.font = 'bold 32px Arial';
- ctx.textAlign = 'center';
- ctx.textBaseline = 'top';
- ctx.fillText('形状涂色练习', canvasWidth / 2, 30);
-
- ctx.font = '20px Arial';
- ctx.fillText('给相同的形状涂上相同的颜色', canvasWidth / 2, 75);
- ctx.restore();
- },
-
- // 绘制上半部分:带颜色的形状示例
- drawUpperSection(ctx, canvasWidth, canvasHeight) {
- const { selectedShapes } = this.data;
- const startY = 120;
- const sectionHeight = canvasHeight * 0.32;
- const shapeSize = 60;
- const cols = Math.min(selectedShapes.length, 6);
- const rows = Math.ceil(selectedShapes.length / cols);
-
- const cellWidth = (canvasWidth - 120) / cols;
- const cellHeight = sectionHeight / Math.max(rows, 1);
-
- selectedShapes.forEach((shape, index) => {
- const row = Math.floor(index / cols);
- const col = index % cols;
-
- const x = 60 + col * cellWidth + cellWidth / 2;
- const y = startY + row * cellHeight + cellHeight / 2;
-
- this.drawShape(ctx, shape, x, y, shapeSize, true);
- });
- },
-
- // 绘制分割线
- drawDividerLine(ctx, canvasWidth, y) {
- ctx.save();
- ctx.strokeStyle = '#333';
- ctx.lineWidth = 2;
- ctx.setLineDash([10, 5]);
- ctx.beginPath();
- ctx.moveTo(60, y);
- ctx.lineTo(canvasWidth - 60, y);
- ctx.stroke();
- ctx.restore();
- },
-
- // 绘制下半部分:无颜色的练习区域
- drawLowerSection(ctx, canvasWidth, canvasHeight) {
- const { selectedShapes } = this.data;
- const startY = canvasHeight * 0.5;
- const sectionHeight = canvasHeight * 0.45;
- const shapeSize = 50;
-
- // 计算网格布局
- const cols = 8;
- const rows = 6;
- const cellWidth = (canvasWidth - 120) / cols;
- const cellHeight = sectionHeight / rows;
-
- // 生成随机形状排列
- const practiceShapes = [];
- const totalShapes = cols * rows;
-
- for (let i = 0; i < totalShapes; i++) {
- const randomShape = selectedShapes[i % selectedShapes.length];
- practiceShapes.push({
- ...randomShape,
- color: 'transparent', // 练习区域不填充颜色
- });
- }
-
- // 打乱顺序
- for (let i = practiceShapes.length - 1; i > 0; i--) {
- const j = Math.floor(Math.random() * (i + 1));
- [practiceShapes[i], practiceShapes[j]] = [
- practiceShapes[j],
- practiceShapes[i],
- ];
- }
-
- practiceShapes.forEach((shape, index) => {
- const row = Math.floor(index / cols);
- const col = index % cols;
-
- const x = 60 + col * cellWidth + cellWidth / 2;
- const y = startY + row * cellHeight + cellHeight / 2;
-
- this.drawShape(ctx, shape, x, y, shapeSize, false);
- });
- },
-
// 保存到相册
saveToAlbum() {
if (!this.data.generatedImage) {
wx.showToast({
- title: '请先生成图片',
+ title: '没有可保存的图片',
icon: 'none',
});
return;
@@ -585,13 +776,23 @@ Page({
filePath: this.data.generatedImage,
success: () => {
wx.showToast({
- title: '保存成功',
+ title: '已保存到相册',
icon: 'success',
});
},
fail: (err) => {
- if (err.errMsg.includes('auth deny')) {
- this.showAuthGuide();
+ console.error('保存失败:', err);
+ if (err.errMsg.includes('auth')) {
+ wx.showModal({
+ title: '提示',
+ content: '需要授权访问相册才能保存图片',
+ confirmText: '去授权',
+ success: (res) => {
+ if (res.confirm) {
+ wx.openSetting();
+ }
+ },
+ });
} else {
wx.showToast({
title: '保存失败',
@@ -602,26 +803,13 @@ Page({
});
},
- // 显示授权引导
- showAuthGuide() {
- wx.showModal({
- title: '权限申请',
- content: '需要相册访问权限才能保存图片,请在设置中开启权限',
- success: (res) => {
- if (res.confirm) {
- wx.openSetting();
- }
- },
- });
- },
-
- // 预览生成的图片
+ // 预览图片
previewImage() {
- if (!this.data.generatedImage) return;
-
- wx.previewImage({
- current: this.data.generatedImage,
- urls: [this.data.generatedImage],
- });
+ if (this.data.generatedImage) {
+ wx.previewImage({
+ urls: [this.data.generatedImage],
+ current: this.data.generatedImage,
+ });
+ }
},
});
diff --git a/miniprogram/demoPages/shapePrint/index.json b/miniprogram/demoPages/shapePrint/index.json
index b686e95..e425a53 100644
--- a/miniprogram/demoPages/shapePrint/index.json
+++ b/miniprogram/demoPages/shapePrint/index.json
@@ -1,7 +1,12 @@
{
- "navigationBarTitleText": "图形绘制 示例",
- "navigationBarBackgroundColor": "#d2e7d8",
+ "navigationBarTitleText": "形状涂色练习生成器",
+ "navigationBarBackgroundColor": "#667eea",
"homeButton": true,
- "backgroundColor": "#e8eddb",
- "enablePullDownRefresh": false
+ "backgroundColor": "#f5f5f5",
+ "enablePullDownRefresh": false,
+ "usingComponents": {
+ "van-popup": "@vant/weapp/popup/index",
+ "van-icon": "@vant/weapp/icon/index",
+ "color-picker": "/components/color-picker/color-picker"
+ }
}
diff --git a/miniprogram/demoPages/shapePrint/index.less b/miniprogram/demoPages/shapePrint/index.less
index 5bc908d..03cb644 100644
--- a/miniprogram/demoPages/shapePrint/index.less
+++ b/miniprogram/demoPages/shapePrint/index.less
@@ -48,24 +48,171 @@
padding-bottom: 15rpx;
}
-.clear-btn {
- background: linear-gradient(45deg, #ff6b6b, #ee5a24);
- color: white;
- border: none;
- padding: 15rpx 25rpx;
+/* 选择形状按钮 */
+.select-shapes-btn {
+ width: 100%;
+ height: 90rpx;
+ font-size: 32rpx;
border-radius: 20rpx;
- font-size: 24rpx;
- box-shadow: 0 4rpx 15rpx rgba(255, 107, 107, 0.4);
+ background: linear-gradient(45deg, #667eea, #764ba2);
+ border: none;
+ color: white;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 8rpx 25rpx rgba(102, 126, 234, 0.4);
+
+ .btn-text {
+ margin-left: 10rpx;
+ font-weight: 500;
+ }
}
-/* 形状选择器 */
-.shape-selector {
+/* 形状卡片容器 */
+.shape-cards-container {
display: grid;
- grid-template-columns: repeat(auto-fill, minmax(200rpx, 1fr));
+ grid-template-columns: 1fr 1fr;
gap: 20rpx;
}
+/* 形状卡片 */
+.shape-card {
+ position: relative;
+ padding: 20rpx;
+ background: linear-gradient(145deg, #ffffff, #f0f0f0);
+ border-radius: 20rpx;
+ border: 2rpx solid #e0e0e0;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ box-shadow: 0 4rpx 15rpx rgba(0, 0, 0, 0.1);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ &:active {
+ transform: scale(0.98);
+ background: linear-gradient(145deg, #f8f9fa, #e9ecef);
+ }
+
+ .delete-btn {
+ position: absolute;
+ top: 10rpx;
+ right: 10rpx;
+ width: 40rpx;
+ height: 40rpx;
+ background: rgba(255, 255, 255, 0.9);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.15);
+ z-index: 10;
+ }
+
+ .shape-preview-container {
+ position: relative;
+ width: 80rpx;
+ height: 80rpx;
+ margin-bottom: 15rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .shape-preview-canvas {
+ position: absolute;
+ width: 80rpx;
+ height: 80rpx;
+ opacity: 0;
+ /* 隐藏,只用于未来可能的Canvas预览 */
+ }
+
+ .shape-name {
+ font-size: 26rpx;
+ color: #333;
+ font-weight: 500;
+ margin-bottom: 10rpx;
+ text-align: center;
+ }
+
+ .color-info {
+ display: flex;
+ align-items: center;
+ gap: 8rpx;
+
+ .color-dot {
+ width: 20rpx;
+ height: 20rpx;
+ border-radius: 50%;
+ border: 2rpx solid #ddd;
+ }
+
+ .color-text {
+ font-size: 22rpx;
+ color: #666;
+ }
+ }
+}
+
+/* 形状选择弹窗样式 */
+.shape-selector-popup {
+ .van-popup {
+ max-height: 80vh;
+ }
+}
+
+.shape-selector-container {
+ padding: 30rpx;
+ max-height: 80vh;
+ overflow-y: auto;
+
+ .popup-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 30rpx;
+ padding-bottom: 20rpx;
+ border-bottom: 2rpx solid #f0f0f0;
+
+ .popup-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ color: #333;
+ }
+
+ .selected-count {
+ font-size: 24rpx;
+ color: #667eea;
+ background: rgba(102, 126, 234, 0.1);
+ padding: 8rpx 15rpx;
+ border-radius: 15rpx;
+ }
+ }
+
+ .shape-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 20rpx;
+ margin-bottom: 30rpx;
+ }
+
+ .popup-actions {
+ padding-top: 20rpx;
+ border-top: 2rpx solid #f0f0f0;
+
+ .confirm-btn {
+ width: 100%;
+ height: 80rpx;
+ font-size: 30rpx;
+ border-radius: 20rpx;
+ background: linear-gradient(45deg, #667eea, #764ba2);
+ }
+ }
+}
+
+/* 弹窗中的形状选项 */
.shape-option {
+ position: relative;
height: 140rpx;
border: 3rpx solid #e0e0e0;
border-radius: 20rpx;
@@ -78,7 +225,7 @@
cursor: pointer;
box-shadow: 0 4rpx 15rpx rgba(0, 0, 0, 0.1);
- &.active {
+ &.selected {
border-color: #667eea;
background: linear-gradient(145deg, #e3f2fd, #bbdefb);
transform: translateY(-5rpx);
@@ -89,6 +236,30 @@
font-weight: bold;
}
}
+
+ &.disabled {
+ opacity: 0.5;
+ background: #f5f5f5;
+ border-color: #ddd;
+
+ .shape-name {
+ color: #999;
+ }
+ }
+
+ .selected-mark {
+ position: absolute;
+ top: 8rpx;
+ right: 8rpx;
+ width: 24rpx;
+ height: 24rpx;
+ background: #667eea;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 10;
+ }
}
.shape-preview-box {
@@ -107,19 +278,22 @@
&.shape-icon-circle {
border-radius: 50%;
- background: transparent;
+ background: var(--fill-color, transparent);
+ border-color: var(--border-color, #666);
}
&.shape-icon-square {
border-radius: 5rpx;
- background: transparent;
+ background: var(--fill-color, transparent);
+ border-color: var(--border-color, #666);
}
&.shape-icon-rectangle {
width: 60rpx;
height: 40rpx;
border-radius: 5rpx;
- background: transparent;
+ background: var(--fill-color, transparent);
+ border-color: var(--border-color, #666);
}
&.shape-icon-triangle {
@@ -128,7 +302,7 @@
border: none;
border-left: 25rpx solid transparent;
border-right: 25rpx solid transparent;
- border-bottom: 45rpx solid #666;
+ border-bottom: 45rpx solid var(--fill-color, red);
background: transparent;
}
@@ -136,7 +310,8 @@
border-radius: 50%;
width: 60rpx;
height: 40rpx;
- background: transparent;
+ background: var(--fill-color, transparent);
+ border-color: var(--border-color, #666);
}
&.shape-icon-diamond {
@@ -146,72 +321,142 @@
border-left: 25rpx solid transparent;
border-right: 25rpx solid transparent;
border-top: 25rpx solid transparent;
- border-bottom: 25rpx solid #666;
+ border-bottom: 25rpx solid var(--fill-color, #666);
background: transparent;
transform: rotate(45deg);
}
+ /* 修正星形 */
&.shape-icon-star {
position: relative;
- width: 0;
- height: 0;
+ width: 80rpx;
+ height: 80rpx;
border: none;
- border-left: 25rpx solid transparent;
- border-right: 25rpx solid transparent;
- border-bottom: 18rpx solid #666;
background: transparent;
- transform: rotate(35deg);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ --star-fill-color: var(--fill-color, red);
+ --star-border-color: var(--border-color, #333);
+ --star-border-width: 2rpx;
+
+ /* 边框层 */
&::before {
content: '';
position: absolute;
- left: -25rpx;
- top: -12rpx;
- width: 0;
- height: 0;
- border-left: 25rpx solid transparent;
- border-right: 25rpx solid transparent;
- border-bottom: 18rpx solid #666;
- transform: rotate(-70deg);
+ left: 50%;
+ top: 50%;
+ width: 66rpx;
+ height: 66rpx;
+ transform: translate(-50%, -50%);
+ background: transparent;
+ border: var(--star-border-width, 2rpx) solid var(--star-border-color, #333);
+ clip-path: polygon(50% 0%,
+ 61% 35%,
+ 98% 35%,
+ 68% 57%,
+ 79% 91%,
+ 50% 70%,
+ 21% 91%,
+ 32% 57%,
+ 2% 35%,
+ 39% 35%);
+ z-index: 1;
+ box-sizing: border-box;
+ }
+
+ &::after {
+ content: '';
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ width: 60rpx;
+ height: 60rpx;
+ transform: translate(-50%, -50%);
+ background: var(--star-fill-color, red);
+ clip-path: polygon(50% 0%,
+ 61% 35%,
+ 98% 35%,
+ 68% 57%,
+ 79% 91%,
+ 50% 70%,
+ 21% 91%,
+ 32% 57%,
+ 2% 35%,
+ 39% 35%);
+ z-index: 2;
+ pointer-events: none;
}
}
+ /* 爱心形状 */
&.shape-icon-heart {
position: relative;
- width: 40rpx;
- height: 35rpx;
- border: none;
- background: #666;
- transform: rotate(-45deg);
+ width: 44rpx;
+ height: 40rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: transparent;
- &::before,
+ /* 主体部分(三角形) */
&::after {
content: '';
position: absolute;
- width: 20rpx;
- height: 30rpx;
- background: #666;
- border-radius: 20rpx 20rpx 0 0;
- transform: rotate(-45deg);
- transform-origin: 0 100%;
+ left: 50%;
+ bottom: 0;
+ transform: translateX(-50%) rotate(-45deg);
+ width: 32rpx;
+ height: 32rpx;
+ background: var(--fill-color, #f00);
+ border-left: 2rpx solid var(--border-color, #333);
+ border-bottom: 2rpx solid var(--border-color, #333);
+ border-bottom-left-radius: 20rpx;
+ border-bottom-right-radius: 20rpx;
+ z-index: 1;
+ clip-path: polygon(0 0, 100% 0, 50% 100%);
}
+ /* 左半圆 */
&::before {
- left: 20rpx;
+ content: '';
+ position: absolute;
+ left: 4rpx;
+ top: 0;
+ width: 24rpx;
+ height: 24rpx;
+ background: var(--fill-color, #f00);
+ border: 2rpx solid var(--border-color, #333);
+ border-bottom: none;
+ border-right: none;
+ border-radius: 50% 50% 0 0;
+ z-index: 2;
}
- &::after {
- top: -15rpx;
- transform: rotate(45deg);
- transform-origin: 100% 100%;
+ /* 右半圆 */
+ .heart-right {
+ position: absolute;
+ right: 4rpx;
+ top: 0;
+ width: 24rpx;
+ height: 24rpx;
+ background: var(--fill-color, #f00);
+ border: 2rpx solid var(--border-color, #333);
+ border-bottom: none;
+ border-left: none;
+ border-radius: 50% 50% 0 0;
+ z-index: 2;
+ content: '';
+ display: block;
}
}
&.shape-icon-hexagon {
width: 40rpx;
height: 22rpx;
- background: #666;
- border: none;
+ background: var(--fill-color, #666);
+ border: 2rpx solid var(--border-color, #333);
position: relative;
&::before,
@@ -226,63 +471,90 @@
&::before {
bottom: 100%;
- border-bottom: 11rpx solid #666;
+ border-bottom: 11rpx solid var(--fill-color, #666);
}
&::after {
top: 100%;
- border-top: 11rpx solid #666;
+ border-top: 11rpx solid var(--fill-color, #666);
}
}
+ /* 修正五边形 */
&.shape-icon-pentagon {
position: relative;
- width: 0;
- height: 0;
- border: none;
- border-left: 25rpx solid transparent;
- border-right: 25rpx solid transparent;
- border-bottom: 30rpx solid #666;
+ width: 40rpx;
+ height: 38rpx;
background: transparent;
+ border: none;
+ display: flex;
+ align-items: center;
+ justify-content: center;
&::before {
content: '';
position: absolute;
- left: -18rpx;
- top: 30rpx;
- width: 36rpx;
- height: 15rpx;
- background: #666;
+ left: 0;
+ top: 0;
+ width: 40rpx;
+ height: 38rpx;
+ background: var(--fill-color, #666);
+ border: 2rpx solid var(--border-color, #333);
+ clip-path: polygon(50% 0%,
+ 100% 38%,
+ 81% 100%,
+ 19% 100%,
+ 0% 38%);
+ box-sizing: border-box;
}
}
+ /* 修正半圆 */
&.shape-icon-semicircle {
width: 50rpx;
height: 25rpx;
- border: 2rpx solid #666;
- border-bottom: none;
- border-radius: 50rpx 50rpx 0 0;
- background: transparent;
- }
-
- &.shape-icon-trapezoid {
- width: 0;
- height: 0;
border: none;
- border-left: 15rpx solid transparent;
- border-right: 15rpx solid transparent;
- border-bottom: 40rpx solid #666;
background: transparent;
position: relative;
+ overflow: hidden;
&::before {
content: '';
position: absolute;
- left: -25rpx;
- top: 40rpx;
+ left: 0;
+ top: 0;
width: 50rpx;
- height: 2rpx;
- background: #666;
+ height: 50rpx;
+ background: var(--fill-color, #666);
+ border: 2rpx solid var(--border-color, #333);
+ border-radius: 50%;
+ box-sizing: border-box;
+ }
+ }
+
+ /* 修正梯形 */
+ &.shape-icon-trapezoid {
+ width: 50rpx;
+ height: 30rpx;
+ border: none;
+ background: transparent;
+ position: relative;
+ overflow: visible;
+
+ &::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 50rpx;
+ height: 30rpx;
+ background: var(--fill-color, #666);
+ border: 2rpx solid var(--border-color, #333);
+ clip-path: polygon(15% 100%,
+ 85% 100%,
+ 100% 0%,
+ 0% 0%);
+ box-sizing: border-box;
}
}
}
diff --git a/miniprogram/demoPages/shapePrint/index.wxml b/miniprogram/demoPages/shapePrint/index.wxml
index f1e2265..e0e25a4 100644
--- a/miniprogram/demoPages/shapePrint/index.wxml
+++ b/miniprogram/demoPages/shapePrint/index.wxml
@@ -5,88 +5,65 @@
为小朋友制作涂色练习页
-
+
- 选择形状
-
-
-
-
-
-
- {{item.name}}
-
-
-
-
-
-
- 选择颜色
-
-
- {{item.name}}
-
-
-
-
-
-
-
-
+
-
- 已选择的形状 ({{selectedShapes.length}})
-
- 清空
-
-
-
+ 已选择的形状 ({{selectedShapes.length}})
+
+ class="shape-card"
+ bindtap="openColorPicker"
+ data-index="{{index}}">
+
-
- {{item.name}}
- {{item.color}}
+ class="delete-btn"
+ catchtap="deleteShape"
+ data-index="{{index}}">
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+ {{item.colorName}}
- 长按删除
-
+
打印设置
-
背景颜色:
@@ -102,17 +79,10 @@
-
-
- 功能说明:
- • 上半部分:带颜色的形状示例
- • 下半部分:无颜色的练习区域
- • 图片大小:A4 纸张,适合打印
-
-
-
+
+
-
-
-
生成的练习页
@@ -144,4 +111,62 @@
bindtap="previewImage" />
点击图片可放大预览 • A4尺寸 • 适合打印
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+
+
+
+
+
+
+
+