fix: font
This commit is contained in:
@@ -37,10 +37,10 @@
|
|||||||
class="selected-title-img"
|
class="selected-title-img"
|
||||||
:src="currentTitle.imageUrl"
|
:src="currentTitle.imageUrl"
|
||||||
mode="widthFix"
|
mode="widthFix"
|
||||||
:style="{
|
:style="titleStyle"
|
||||||
transform: `translate(${titleOffsetX}rpx, ${titleOffsetY}rpx) scale(${titleScale})`,
|
@touchstart.stop="handleTitleTouchStart"
|
||||||
top: '40rpx'
|
@touchmove.stop="handleTitleTouchMove"
|
||||||
}"
|
@touchend.stop="handleTitleTouchEnd"
|
||||||
/>
|
/>
|
||||||
<view
|
<view
|
||||||
class="bubble"
|
class="bubble"
|
||||||
@@ -421,9 +421,100 @@ const currentTitle = ref(null);
|
|||||||
const titlePage = ref(1);
|
const titlePage = ref(1);
|
||||||
const loadingTitles = ref(false);
|
const loadingTitles = ref(false);
|
||||||
const hasMoreTitles = ref(true);
|
const hasMoreTitles = ref(true);
|
||||||
const titleOffsetX = ref(0);
|
const titleState = ref({
|
||||||
const titleOffsetY = ref(0);
|
offsetX: 0,
|
||||||
const titleScale = ref(1);
|
offsetY: 0,
|
||||||
|
scale: 1,
|
||||||
|
rotate: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const titleStyle = computed(() => {
|
||||||
|
return {
|
||||||
|
transform: `translate(${titleState.value.offsetX}rpx, ${titleState.value.offsetY}rpx) scale(${titleState.value.scale}) rotate(${titleState.value.rotate}deg)`,
|
||||||
|
top: '40rpx',
|
||||||
|
pointerEvents: 'auto',
|
||||||
|
transition: 'none'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 缓存比例转换
|
||||||
|
const sysInfo = uni.getSystemInfoSync();
|
||||||
|
const pxToRpx = 750 / sysInfo.windowWidth;
|
||||||
|
|
||||||
|
// 标题触摸交互相关
|
||||||
|
let startTouches = [];
|
||||||
|
let initialTitleState = {
|
||||||
|
offsetX: 0,
|
||||||
|
offsetY: 0,
|
||||||
|
scale: 1,
|
||||||
|
rotate: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDistance = (p1, p2) => {
|
||||||
|
const x = p2.clientX - p1.clientX;
|
||||||
|
const y = p2.clientY - p1.clientY;
|
||||||
|
return Math.sqrt(x * x + y * y);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAngle = (p1, p2) => {
|
||||||
|
const x = p1.clientX - p2.clientX;
|
||||||
|
const y = p1.clientY - p2.clientY;
|
||||||
|
return (Math.atan2(y, x) * 180) / Math.PI;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTitleTouchStart = (e) => {
|
||||||
|
if (!currentTitle.value) return;
|
||||||
|
startTouches = e.touches;
|
||||||
|
initialTitleState = { ...titleState.value };
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTitleTouchEnd = () => {
|
||||||
|
startTouches = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTitleTouchMove = (e) => {
|
||||||
|
if (!currentTitle.value || !startTouches.length) return;
|
||||||
|
|
||||||
|
if (e.touches.length === 1 && startTouches.length === 1) {
|
||||||
|
// 单指拖拽
|
||||||
|
const moveX = e.touches[0].clientX - startTouches[0].clientX;
|
||||||
|
const moveY = e.touches[0].clientY - startTouches[0].clientY;
|
||||||
|
|
||||||
|
titleState.value.offsetX = initialTitleState.offsetX + moveX * pxToRpx;
|
||||||
|
titleState.value.offsetY = initialTitleState.offsetY + moveY * pxToRpx;
|
||||||
|
} else if (e.touches.length === 2 && startTouches.length === 2) {
|
||||||
|
// 双指缩放+平移+旋转
|
||||||
|
const p1 = e.touches[0];
|
||||||
|
const p2 = e.touches[1];
|
||||||
|
const startP1 = startTouches[0];
|
||||||
|
const startP2 = startTouches[1];
|
||||||
|
|
||||||
|
// 缩放
|
||||||
|
const currentDist = getDistance(p1, p2);
|
||||||
|
const startDist = getDistance(startP1, startP2);
|
||||||
|
if (startDist > 0) {
|
||||||
|
const scale = initialTitleState.scale * (currentDist / startDist);
|
||||||
|
titleState.value.scale = Math.min(Math.max(scale, 0.2), 3.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 旋转
|
||||||
|
const currentAngle = getAngle(p1, p2);
|
||||||
|
const startAngle = getAngle(startP1, startP2);
|
||||||
|
titleState.value.rotate = initialTitleState.rotate + (currentAngle - startAngle);
|
||||||
|
|
||||||
|
// 平移
|
||||||
|
const currentCenterX = (p1.clientX + p2.clientX) / 2;
|
||||||
|
const currentCenterY = (p1.clientY + p2.clientY) / 2;
|
||||||
|
const startCenterX = (startP1.clientX + startP2.clientX) / 2;
|
||||||
|
const startCenterY = (startP1.clientY + startP2.clientY) / 2;
|
||||||
|
|
||||||
|
const moveX = currentCenterX - startCenterX;
|
||||||
|
const moveY = currentCenterY - startCenterY;
|
||||||
|
|
||||||
|
titleState.value.offsetX = initialTitleState.offsetX + moveX * pxToRpx;
|
||||||
|
titleState.value.offsetY = initialTitleState.offsetY + moveY * pxToRpx;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const targetName = ref("祝您");
|
const targetName = ref("祝您");
|
||||||
const signatureName = ref(userStore?.userInfo?.nickName || "xxx");
|
const signatureName = ref(userStore?.userInfo?.nickName || "xxx");
|
||||||
@@ -750,6 +841,13 @@ const selectTitle = (title) => {
|
|||||||
currentTitle.value = null;
|
currentTitle.value = null;
|
||||||
} else {
|
} else {
|
||||||
currentTitle.value = title;
|
currentTitle.value = title;
|
||||||
|
// 切换标题时重置位置和缩放
|
||||||
|
titleState.value = {
|
||||||
|
offsetX: 0,
|
||||||
|
offsetY: 0,
|
||||||
|
scale: 1,
|
||||||
|
rotate: 0,
|
||||||
|
};
|
||||||
closePanel();
|
closePanel();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -884,12 +982,26 @@ const saveByCanvas = async (save = true) => {
|
|||||||
// 3️⃣ 标题图片
|
// 3️⃣ 标题图片
|
||||||
if (titleImg) {
|
if (titleImg) {
|
||||||
const previewBaseWidth = 400; // rpx
|
const previewBaseWidth = 400; // rpx
|
||||||
const drawWidth = r2p(previewBaseWidth) * titleScale.value;
|
const drawWidth = r2p(previewBaseWidth) * titleState.value.scale;
|
||||||
const drawHeight = (titleImg.height / titleImg.width) * drawWidth;
|
const drawHeight = (titleImg.height / titleImg.width) * drawWidth;
|
||||||
// 预览中是 translate(offsetX, offsetY),top: 40rpx
|
|
||||||
const titleX = (W - drawWidth) / 2 + r2p(titleOffsetX.value);
|
ctx.save();
|
||||||
const titleY = r2p(40 + titleOffsetY.value);
|
// 计算中心点:容器中点 + 偏移量
|
||||||
ctx.drawImage(titleImg, titleX, titleY, drawWidth, drawHeight);
|
const centerX = W / 2 + r2p(titleState.value.offsetX);
|
||||||
|
const centerY = r2p(40) + drawHeight / 2 + r2p(titleState.value.offsetY);
|
||||||
|
|
||||||
|
ctx.translate(centerX, centerY);
|
||||||
|
ctx.rotate((titleState.value.rotate * Math.PI) / 180);
|
||||||
|
|
||||||
|
// 绘制图片,使图片中心位于 translate 后的 (0,0)
|
||||||
|
ctx.drawImage(
|
||||||
|
titleImg,
|
||||||
|
-drawWidth / 2,
|
||||||
|
-drawHeight / 2,
|
||||||
|
drawWidth,
|
||||||
|
drawHeight
|
||||||
|
);
|
||||||
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4️⃣ 祝福语气泡
|
// 4️⃣ 祝福语气泡
|
||||||
@@ -1428,7 +1540,8 @@ function drawRoundRect(ctx, x, y, w, h, r, color) {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
width: 400rpx;
|
width: 400rpx;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
transition: transform 0.1s;
|
/* 移除 transition,防止拖拽抖动 */
|
||||||
|
transition: none;
|
||||||
}
|
}
|
||||||
.tpl-card.selected {
|
.tpl-card.selected {
|
||||||
outline: 4rpx solid #ff3b30;
|
outline: 4rpx solid #ff3b30;
|
||||||
|
|||||||
Reference in New Issue
Block a user