feat: 测试图形绘制
This commit is contained in:
@@ -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],
|
||||
});
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user