diff --git a/miniprogram/demoPages/shapePrint/index.js b/miniprogram/demoPages/shapePrint/index.js
index 8e56018..b4b2ef3 100644
--- a/miniprogram/demoPages/shapePrint/index.js
+++ b/miniprogram/demoPages/shapePrint/index.js
@@ -35,14 +35,68 @@ Page({
onLoad() {
console.log('形状绘制页面加载完成');
+
+ // 为可选形状生成SVG内容
+ const shapesWithSVG = this.data.availableShapes.map((shape) => ({
+ ...shape,
+ svgContent: this.createSVGElement(shape, 'transparent', '#333', 50),
+ }));
+
// 初始化临时选择列表
this.setData({
+ availableShapes: shapesWithSVG,
tempSelectedShapeIds: this.data.selectedShapes.map(
(shape) => shape.id,
),
});
},
+ // 生成带颜色的SVG字符串
+ generateColoredSVG(shape, fillColor = '#666', borderColor = '#333') {
+ if (!shape || !shape.svg) return '';
+
+ let svg = shape.svg;
+
+ // 替换stroke属性
+ svg = svg.replace(/stroke="[^"]*"/g, `stroke="${borderColor}"`);
+
+ // 处理fill属性
+ if (fillColor && fillColor !== 'transparent') {
+ svg = svg.replace(/fill="[^"]*"/g, `fill="${fillColor}"`);
+ }
+
+ // 确保stroke-width存在
+ if (!svg.includes('stroke-width')) {
+ svg = svg.replace(
+ /(<(?:circle|rect|polygon|ellipse|path|line)[^>]*?)>/g,
+ '$1 stroke-width="2">',
+ );
+ }
+
+ return svg;
+ },
+
+ // 创建SVG的base64数据URL
+ createSVGElement(shape, fillColor, borderColor, size = 60) {
+ const coloredSVG = this.generateColoredSVG(
+ shape,
+ fillColor,
+ borderColor,
+ );
+
+ const svgContent = ``;
+
+ // 转换为base64
+ const base64 = wx.arrayBufferToBase64(
+ new TextEncoder().encode(svgContent),
+ );
+
+ // 可选:调试日志(发布时移除)
+ // console.log(`Creating SVG for ${shape.name}:`, { svgContent });
+
+ return `data:image/svg+xml;base64,${base64}`;
+ },
+
// 打开形状选择器
openShapeSelector() {
this.setData({
@@ -107,8 +161,17 @@ Page({
(s) => s.shapeId === shapeId,
);
if (existingShape) {
- // 保持原有颜色
- newSelectedShapes.push(existingShape);
+ // 保持原有颜色,更新SVG内容
+ const updatedShape = {
+ ...existingShape,
+ svgContent: this.createSVGElement(
+ shape,
+ existingShape.fillColor,
+ '#333',
+ 60,
+ ),
+ };
+ newSelectedShapes.push(updatedShape);
const colorIndex = this.data.basic12Colors.findIndex(
(c) => c.hex === existingShape.fillColor,
);
@@ -119,14 +182,21 @@ Page({
// 新形状,分配随机颜色
const randomColor =
this.getRandomUnusedColor(usedColorIndexes);
- newSelectedShapes.push({
+ const newShape = {
id: Date.now() + index,
shapeId: shape.id,
name: shape.name,
fillColor: randomColor.hex,
colorName: randomColor.name,
drawFunction: shape.drawFunction,
- });
+ svgContent: this.createSVGElement(
+ shape,
+ randomColor.hex,
+ '#333',
+ 60,
+ ),
+ };
+ newSelectedShapes.push(newShape);
}
}
});
@@ -250,6 +320,10 @@ Page({
if (currentEditingIndex >= 0) {
const newSelectedShapes = [...selectedShapes];
+ const currentShape = newSelectedShapes[currentEditingIndex];
+ const shapeDefinition = this.data.availableShapes.find(
+ (s) => s.id === currentShape.shapeId,
+ );
const colorInfo = basic12Colors.find((c) => c.hex === color) ||
WATER_COLORS.extended24.find((c) => c.hex === color) || {
name: '自定义色',
@@ -257,9 +331,15 @@ Page({
};
newSelectedShapes[currentEditingIndex] = {
- ...newSelectedShapes[currentEditingIndex],
+ ...currentShape,
fillColor: color,
colorName: colorInfo.name,
+ svgContent: this.createSVGElement(
+ shapeDefinition,
+ color,
+ '#333',
+ 60,
+ ),
};
this.setData(
@@ -338,19 +418,29 @@ Page({
this.drawPracticeArea(ctx, width, height);
// 导出图片
- const tempFilePath = canvas.toTempFilePathSync({
+ wx.canvasToTempFilePath({
+ canvas: canvas,
fileType: 'png',
quality: 1,
- });
+ success: (res) => {
+ this.setData({
+ generatedImage: res.tempFilePath,
+ isGenerating: false,
+ });
- this.setData({
- generatedImage: tempFilePath,
- isGenerating: false,
- });
-
- wx.showToast({
- title: '生成完成',
- icon: 'success',
+ wx.showToast({
+ title: '生成完成',
+ icon: 'success',
+ });
+ },
+ fail: (error) => {
+ console.error('导出图片失败:', error);
+ this.setData({ isGenerating: false });
+ wx.showToast({
+ title: '生成失败,请重试',
+ icon: 'none',
+ });
+ },
});
} catch (error) {
console.error('生成图片失败:', error);
diff --git a/miniprogram/demoPages/shapePrint/index.less b/miniprogram/demoPages/shapePrint/index.less
index 336d1b9..d123c37 100644
--- a/miniprogram/demoPages/shapePrint/index.less
+++ b/miniprogram/demoPages/shapePrint/index.less
@@ -271,502 +271,21 @@
justify-content: center;
}
-.shape-icon {
+/* SVG 样式 */
+.shape-svg {
+ width: 60rpx;
+ height: 60rpx;
+ display: block;
+}
+
+.shape-svg-small {
width: 50rpx;
height: 50rpx;
- border: 2rpx solid #666;
-
- &.shape-icon-circle {
- border-radius: 50%;
- background: var(--fill-color, transparent);
- border-color: var(--border-color, #666);
- }
-
- &.shape-icon-square {
- border-radius: 5rpx;
- background: var(--fill-color, transparent);
- border-color: var(--border-color, #666);
- }
-
- &.shape-icon-rectangle {
- width: 60rpx;
- height: 40rpx;
- border-radius: 5rpx;
- background: var(--fill-color, transparent);
- border-color: var(--border-color, #666);
- }
-
- &.shape-icon-triangle {
- width: 0;
- height: 0;
- border: none;
- border-left: 25rpx solid transparent;
- border-right: 25rpx solid transparent;
- border-bottom: 45rpx solid var(--fill-color, red);
- background: transparent;
- }
-
- &.shape-icon-oval {
- border-radius: 50%;
- width: 60rpx;
- height: 40rpx;
- background: var(--fill-color, transparent);
- border-color: var(--border-color, #666);
- }
-
- &.shape-icon-diamond {
- width: 0;
- height: 0;
- border: none;
- border-left: 25rpx solid transparent;
- border-right: 25rpx solid transparent;
- border-top: 25rpx solid transparent;
- border-bottom: 25rpx solid var(--fill-color, #666);
- background: transparent;
- transform: rotate(45deg);
- }
-
- /* 修正星形 */
- &.shape-icon-star {
- position: relative;
- width: 80rpx;
- height: 80rpx;
- border: none;
- background: transparent;
- 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: 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: 44rpx;
- height: 40rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- background: transparent;
-
- /* 主体部分(三角形) */
- &::after {
- content: '';
- position: absolute;
- 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 {
- 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;
- }
-
- /* 右半圆 */
- .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;
- }
- }
-
- &.shape-icon-hexagon {
- width: 40rpx;
- height: 22rpx;
- background: var(--fill-color, #666);
- border: 2rpx solid var(--border-color, #333);
- position: relative;
-
- &::before,
- &::after {
- content: '';
- position: absolute;
- width: 0;
- height: 0;
- border-left: 20rpx solid transparent;
- border-right: 20rpx solid transparent;
- }
-
- &::before {
- bottom: 100%;
- border-bottom: 11rpx solid var(--fill-color, #666);
- }
-
- &::after {
- top: 100%;
- border-top: 11rpx solid var(--fill-color, #666);
- }
- }
-
- /* 修正五边形 */
- &.shape-icon-pentagon {
- position: relative;
- width: 40rpx;
- height: 38rpx;
- background: transparent;
- border: none;
- display: flex;
- align-items: center;
- justify-content: center;
-
- &::before {
- content: '';
- position: absolute;
- 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: none;
- background: transparent;
- position: relative;
- overflow: hidden;
-
- &::before {
- content: '';
- position: absolute;
- left: 0;
- top: 0;
- width: 50rpx;
- 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;
- }
- }
-
- // === 3D 形状样式 ===
-
- /* 圆柱体 */
- &.shape-icon-cylinder {
- width: 60rpx;
- height: 60rpx;
- border: none;
- background: transparent;
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
-
- /* 顶部椭圆 */
- &::before {
- content: '';
- position: absolute;
- top: 0;
- left: 50%;
- transform: translateX(-50%);
- width: 50rpx;
- height: 16rpx;
- background: var(--fill-color, #666);
- border: 2rpx solid var(--border-color, #333);
- border-radius: 50%;
- z-index: 3;
- }
-
- /* 主体圆柱 */
- &::after {
- content: '';
- position: absolute;
- top: 8rpx;
- left: 50%;
- transform: translateX(-50%);
- width: 50rpx;
- height: 44rpx;
- background: var(--fill-color, #666);
- border-left: 2rpx solid var(--border-color, #333);
- border-right: 2rpx solid var(--border-color, #333);
- z-index: 1;
- }
-
- /* 底部椭圆 */
- .cylinder-bottom {
- position: absolute;
- bottom: 0;
- left: 50%;
- transform: translateX(-50%);
- width: 50rpx;
- height: 16rpx;
- background: var(--fill-color, #666);
- border: 2rpx solid var(--border-color, #333);
- border-radius: 50%;
- z-index: 2;
- }
- }
-
- /* 正方体 */
- &.shape-icon-cube {
- width: 60rpx;
- height: 60rpx;
- border: none;
- background: transparent;
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
-
- /* 正面 */
- &::before {
- content: '';
- position: absolute;
- bottom: 0;
- left: 0;
- width: 40rpx;
- height: 40rpx;
- background: var(--fill-color, #666);
- border: 2rpx solid var(--border-color, #333);
- z-index: 3;
- }
-
- /* 顶面 */
- &::after {
- content: '';
- position: absolute;
- top: 0;
- right: 0;
- width: 40rpx;
- height: 40rpx;
- background: var(--fill-color, #666);
- border: 2rpx solid var(--border-color, #333);
- transform: skewX(-30deg) scaleY(0.6);
- transform-origin: bottom left;
- z-index: 2;
- opacity: 0.8;
- }
-
- /* 右面 */
- .cube-right {
- position: absolute;
- bottom: 0;
- right: 0;
- width: 20rpx;
- height: 40rpx;
- background: var(--fill-color, #666);
- border: 2rpx solid var(--border-color, #333);
- border-left: none;
- transform: skewY(-30deg);
- transform-origin: bottom left;
- z-index: 1;
- opacity: 0.6;
- }
- }
-
- /* 球体 */
- &.shape-icon-sphere {
- width: 50rpx;
- height: 50rpx;
- border: 2rpx solid var(--border-color, #333);
- border-radius: 50%;
- background: var(--fill-color, #666);
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
-
- /* 高光 */
- &::before {
- content: '';
- position: absolute;
- top: 12rpx;
- left: 16rpx;
- width: 12rpx;
- height: 8rpx;
- background: rgba(255, 255, 255, 0.6);
- border-radius: 50%;
- }
-
- /* 纬线 */
- &::after {
- content: '';
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- width: 46rpx;
- height: 20rpx;
- border: 1rpx solid var(--border-color, #333);
- border-radius: 50%;
- opacity: 0.3;
- }
- }
-
- /* 圆锥体 */
- &.shape-icon-cone {
- width: 60rpx;
- height: 60rpx;
- border: none;
- background: transparent;
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
-
- /* 圆锥主体 */
- &::before {
- content: '';
- position: absolute;
- top: 0;
- left: 50%;
- transform: translateX(-50%);
- width: 0;
- height: 0;
- border-left: 25rpx solid transparent;
- border-right: 25rpx solid transparent;
- border-bottom: 45rpx solid var(--fill-color, #666);
- z-index: 2;
- }
-
- /* 圆锥边框 */
- &::after {
- content: '';
- position: absolute;
- top: -1rpx;
- left: 50%;
- transform: translateX(-50%);
- width: 0;
- height: 0;
- border-left: 26rpx solid transparent;
- border-right: 26rpx solid transparent;
- border-bottom: 46rpx solid var(--border-color, #333);
- z-index: 1;
- }
-
- /* 底部椭圆 */
- .cone-bottom {
- position: absolute;
- bottom: 0;
- left: 50%;
- transform: translateX(-50%);
- width: 50rpx;
- height: 16rpx;
- background: var(--fill-color, #666);
- border: 2rpx solid var(--border-color, #333);
- border-radius: 50%;
- z-index: 3;
- }
- }
+ display: block;
}
+/* 保留基础样式,移除所有形状相关的CSS */
+
.shape-name {
font-size: 24rpx;
color: #666;
diff --git a/miniprogram/demoPages/shapePrint/index.wxml b/miniprogram/demoPages/shapePrint/index.wxml
index 1c95cf0..f101257 100644
--- a/miniprogram/demoPages/shapePrint/index.wxml
+++ b/miniprogram/demoPages/shapePrint/index.wxml
@@ -37,32 +37,11 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
{{item.name}}
@@ -158,24 +137,11 @@
-
-
-
-
-
-
-
-
-
-
+
+
{{item.name}}