From e0f68a9f7117a2db623e390b6e3c569b91d830b8 Mon Sep 17 00:00:00 2001 From: joey Date: Tue, 22 Jul 2025 17:16:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B5=8B=E8=AF=95=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- miniprogram/demoPages/shapePrint/index.js | 198 ++++++++++++++++++ miniprogram/demoPages/shapePrint/index.less | 212 +++++++++++++++++++- miniprogram/demoPages/shapePrint/index.wxml | 35 +++- miniprogram/demoPages/shapePrint/shapes.js | 29 +++ 4 files changed, 471 insertions(+), 3 deletions(-) diff --git a/miniprogram/demoPages/shapePrint/index.js b/miniprogram/demoPages/shapePrint/index.js index 69af751..8e56018 100644 --- a/miniprogram/demoPages/shapePrint/index.js +++ b/miniprogram/demoPages/shapePrint/index.js @@ -504,6 +504,18 @@ Page({ case 'drawTrapezoid': this.drawTrapezoid(ctx, x, y, size, color, '#333', filled); break; + case 'drawCylinder': + this.drawCylinder(ctx, x, y, size, color, '#333', filled); + break; + case 'drawCube': + this.drawCube(ctx, x, y, size, color, '#333', filled); + break; + case 'drawSphere': + this.drawSphere(ctx, x, y, size, color, '#333', filled); + break; + case 'drawCone': + this.drawCone(ctx, x, y, size, color, '#333', filled); + break; } }, @@ -762,6 +774,192 @@ Page({ ctx.restore(); }, + // === 3D形状绘制函数 === + + // 绘制圆柱体 + drawCylinder(ctx, x, y, size, fillColor, borderColor, filled = true) { + ctx.save(); + const radius = size * 0.3; + const height = size * 0.6; + + // 绘制主体 + if (filled && fillColor !== 'transparent') { + ctx.fillStyle = fillColor; + ctx.fillRect(x - radius, y - height / 2, radius * 2, height); + } + + // 绘制主体边框 + ctx.strokeStyle = borderColor; + ctx.lineWidth = 3; + ctx.beginPath(); + ctx.moveTo(x - radius, y - height / 2); + ctx.lineTo(x - radius, y + height / 2); + ctx.moveTo(x + radius, y - height / 2); + ctx.lineTo(x + radius, y + height / 2); + ctx.stroke(); + + // 绘制顶部椭圆 + ctx.beginPath(); + ctx.ellipse(x, y - height / 2, radius, radius * 0.3, 0, 0, Math.PI * 2); + if (filled && fillColor !== 'transparent') { + ctx.fillStyle = fillColor; + ctx.fill(); + } + ctx.stroke(); + + // 绘制底部椭圆 + ctx.beginPath(); + ctx.ellipse(x, y + height / 2, radius, radius * 0.3, 0, 0, Math.PI * 2); + if (filled && fillColor !== 'transparent') { + ctx.fillStyle = fillColor; + ctx.fill(); + } + ctx.stroke(); + + ctx.restore(); + }, + + // 绘制正方体 + drawCube(ctx, x, y, size, fillColor, borderColor, filled = true) { + ctx.save(); + const cubeSize = size * 0.4; + const offset = cubeSize * 0.3; // 3D偏移量 + + // 绘制后面(右侧面) + if (filled && fillColor !== 'transparent') { + ctx.fillStyle = fillColor; + ctx.globalAlpha = 0.6; // 较暗 + ctx.fillRect( + x - cubeSize / 2 + offset, + y - cubeSize / 2 - offset, + cubeSize, + cubeSize, + ); + ctx.globalAlpha = 1; + } + + ctx.strokeStyle = borderColor; + ctx.lineWidth = 2; + ctx.strokeRect( + x - cubeSize / 2 + offset, + y - cubeSize / 2 - offset, + cubeSize, + cubeSize, + ); + + // 绘制前面(正面) + if (filled && fillColor !== 'transparent') { + ctx.fillStyle = fillColor; + ctx.fillRect( + x - cubeSize / 2, + y - cubeSize / 2, + cubeSize, + cubeSize, + ); + } + + ctx.strokeRect(x - cubeSize / 2, y - cubeSize / 2, cubeSize, cubeSize); + + // 绘制连接线 + ctx.beginPath(); + // 左上角连接线 + ctx.moveTo(x - cubeSize / 2, y - cubeSize / 2); + ctx.lineTo(x - cubeSize / 2 + offset, y - cubeSize / 2 - offset); + // 右上角连接线 + ctx.moveTo(x + cubeSize / 2, y - cubeSize / 2); + ctx.lineTo(x + cubeSize / 2 + offset, y - cubeSize / 2 - offset); + // 右下角连接线 + ctx.moveTo(x + cubeSize / 2, y + cubeSize / 2); + ctx.lineTo(x + cubeSize / 2 + offset, y + cubeSize / 2 - offset); + ctx.stroke(); + + ctx.restore(); + }, + + // 绘制球体 + drawSphere(ctx, x, y, size, fillColor, borderColor, filled = true) { + ctx.save(); + const radius = size * 0.4; + + // 绘制主体圆形 + ctx.beginPath(); + ctx.arc(x, y, radius, 0, Math.PI * 2); + + if (filled && fillColor !== 'transparent') { + // 创建径向渐变模拟3D效果 + const gradient = ctx.createRadialGradient( + x - radius * 0.3, + y - radius * 0.3, + 0, + x, + y, + radius, + ); + gradient.addColorStop(0, '#ffffff'); + gradient.addColorStop(0.3, fillColor); + gradient.addColorStop(1, '#000000'); + ctx.fillStyle = gradient; + ctx.fill(); + } + + ctx.strokeStyle = borderColor; + ctx.lineWidth = 3; + ctx.stroke(); + + // 绘制纬线 + ctx.strokeStyle = borderColor; + ctx.lineWidth = 1; + ctx.globalAlpha = 0.5; + + // 水平纬线 + ctx.beginPath(); + ctx.ellipse(x, y, radius, radius * 0.3, 0, 0, Math.PI * 2); + ctx.stroke(); + + // 垂直经线 + ctx.beginPath(); + ctx.ellipse(x, y, radius * 0.3, radius, 0, 0, Math.PI * 2); + ctx.stroke(); + + ctx.restore(); + }, + + // 绘制圆锥体 + drawCone(ctx, x, y, size, fillColor, borderColor, filled = true) { + ctx.save(); + const radius = size * 0.3; + const height = size * 0.6; + + // 绘制圆锥主体 + ctx.beginPath(); + ctx.moveTo(x, y - height / 2); // 顶点 + ctx.lineTo(x - radius, y + height / 2); // 左下 + ctx.lineTo(x + radius, y + height / 2); // 右下 + ctx.closePath(); + + if (filled && fillColor !== 'transparent') { + ctx.fillStyle = fillColor; + ctx.fill(); + } + + ctx.strokeStyle = borderColor; + ctx.lineWidth = 3; + ctx.stroke(); + + // 绘制底部椭圆 + ctx.beginPath(); + ctx.ellipse(x, y + height / 2, radius, radius * 0.3, 0, 0, Math.PI * 2); + + if (filled && fillColor !== 'transparent') { + ctx.fillStyle = fillColor; + ctx.fill(); + } + + ctx.stroke(); + + ctx.restore(); + }, + // 保存到相册 saveToAlbum() { if (!this.data.generatedImage) { diff --git a/miniprogram/demoPages/shapePrint/index.less b/miniprogram/demoPages/shapePrint/index.less index 03cb644..336d1b9 100644 --- a/miniprogram/demoPages/shapePrint/index.less +++ b/miniprogram/demoPages/shapePrint/index.less @@ -447,8 +447,6 @@ border-left: none; border-radius: 50% 50% 0 0; z-index: 2; - content: ''; - display: block; } } @@ -557,6 +555,216 @@ 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; + } + } } .shape-name { diff --git a/miniprogram/demoPages/shapePrint/index.wxml b/miniprogram/demoPages/shapePrint/index.wxml index e0e25a4..1c95cf0 100644 --- a/miniprogram/demoPages/shapePrint/index.wxml +++ b/miniprogram/demoPages/shapePrint/index.wxml @@ -46,6 +46,22 @@ + + + + + + + + @@ -142,7 +158,24 @@ - + + + + + + + + + + {{item.name}} diff --git a/miniprogram/demoPages/shapePrint/shapes.js b/miniprogram/demoPages/shapePrint/shapes.js index 90384ff..61316e0 100644 --- a/miniprogram/demoPages/shapePrint/shapes.js +++ b/miniprogram/demoPages/shapePrint/shapes.js @@ -84,6 +84,35 @@ const shapes = [ svg: '', drawFunction: 'drawTrapezoid', }, + // 新增3D形状 + { + id: 'cylinder', + name: '圆柱体', + type: '3d-cylinder', + svg: '', + drawFunction: 'drawCylinder', + }, + { + id: 'cube', + name: '正方体', + type: '3d-cube', + svg: '', + drawFunction: 'drawCube', + }, + { + id: 'sphere', + name: '球体', + type: '3d-sphere', + svg: '', + drawFunction: 'drawSphere', + }, + { + id: 'cone', + name: '圆锥体', + type: '3d-cone', + svg: '', + drawFunction: 'drawCone', + }, ]; // 颜色选项