fix(diy): 贴纸尺寸归一化画布空间 + 坐标钳制 + 旧数据读端兼容
修正工作流批次②(问题1 重叠误报): - addSticker 按 mask 短边 60% 归一化 width/height(契约实现注记: width/height 语义 = 画布显示像素),渲染/碰撞/WCD 三方自洽 - 拖动与缩放后坐标钳制在 [0, mask尺寸-显示尺寸],杜绝负坐标/拖出画布 - 读取端兼容:旧数据 width > mask 尺寸时按 mask 等比归一化(不做存量迁移) - canvas-image/preview-image 补 transform-origin: top left, 缩放原点与碰撞盒(左上角)语义一致 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -103,6 +103,8 @@
|
||||
position: absolute;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
/* 问题1 修正:碰撞盒按左上角计算,缩放原点统一为左上角,渲染与碰撞语义自洽 */
|
||||
transform-origin: top left;
|
||||
z-index: 5;
|
||||
border: 2rpx solid transparent;
|
||||
border-radius: 8rpx;
|
||||
@@ -391,6 +393,7 @@
|
||||
position: absolute;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
transform-origin: top left;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
|
||||
+49
-14
@@ -88,16 +88,30 @@ export default function DIYPage() {
|
||||
setQuantity(design.count)
|
||||
const product = getProductById(design.productId)
|
||||
if (product) setCategory(product)
|
||||
if (design.designData ? design.designData.stickers : undefined) {
|
||||
setStickers(design.designData.stickers)
|
||||
} else if (design.designData ? design.designData.imageSrc : undefined) {
|
||||
const dd = design.designData
|
||||
const rawStickers = dd ? dd.stickers : undefined
|
||||
if (rawStickers) {
|
||||
// 问题1 留意点:旧数据 width/height 为图片原始像素语义,读取端按 mask 等比归一化
|
||||
//(契约实现注记,不做存量迁移);新语义数据(≤mask 短边 60%)原样通过
|
||||
const mask = (dd && dd.category && dd.category.mask) || (product ? product.mask : undefined)
|
||||
const normalized: StickerItem[] = mask
|
||||
? rawStickers.map(s => {
|
||||
if (s.width > mask.width || s.height > mask.height) {
|
||||
const k = (Math.min(mask.width, mask.height) * 0.6) / Math.max(s.width, s.height)
|
||||
return { ...s, width: Math.round(s.width * k), height: Math.round(s.height * k) }
|
||||
}
|
||||
return s
|
||||
})
|
||||
: rawStickers
|
||||
setStickers(normalized)
|
||||
} else if (dd ? dd.imageSrc : undefined) {
|
||||
// 兼容旧版数据
|
||||
const s: StickerItem = {
|
||||
id: 'legacy_' + Date.now(),
|
||||
src: design.designData.imageSrc,
|
||||
x: design.designData.imagePos ? design.designData.imagePos.x || 0 : 0,
|
||||
y: design.designData.imagePos ? design.designData.imagePos.y || 0 : 0,
|
||||
scale: design.designData.imagePos ? design.designData.imagePos.scale || 1 : 1,
|
||||
src: dd.imageSrc,
|
||||
x: dd.imagePos ? dd.imagePos.x || 0 : 0,
|
||||
y: dd.imagePos ? dd.imagePos.y || 0 : 0,
|
||||
scale: dd.imagePos ? dd.imagePos.scale || 1 : 1,
|
||||
width: 200,
|
||||
height: 200,
|
||||
isOverlapping: false
|
||||
@@ -207,14 +221,17 @@ export default function DIYPage() {
|
||||
Taro.getImageInfo({
|
||||
src,
|
||||
success: (info) => {
|
||||
// 问题1 修正:归一化到画布坐标空间(width/height = 画布显示像素,契约实现注记)
|
||||
const maskMin = Math.min(category.mask.width, category.mask.height)
|
||||
const k = (maskMin * 0.6) / Math.max(info.width, info.height)
|
||||
const newSticker: StickerItem = {
|
||||
id: 'stk_' + Date.now(),
|
||||
src,
|
||||
x: 0,
|
||||
y: 0,
|
||||
scale: 1,
|
||||
width: info.width,
|
||||
height: info.height,
|
||||
width: Math.round(info.width * k),
|
||||
height: Math.round(info.height * k),
|
||||
isOverlapping: false
|
||||
}
|
||||
const next = [...stickers, newSticker]
|
||||
@@ -223,15 +240,17 @@ export default function DIYPage() {
|
||||
setActiveStickerId(newSticker.id)
|
||||
},
|
||||
fail: () => {
|
||||
// fallback 尺寸
|
||||
// fallback 尺寸(同样按画布空间归一化)
|
||||
const maskMin = Math.min(category.mask.width, category.mask.height)
|
||||
const k = (maskMin * 0.6) / 200
|
||||
const newSticker: StickerItem = {
|
||||
id: 'stk_' + Date.now(),
|
||||
src,
|
||||
x: 0,
|
||||
y: 0,
|
||||
scale: 1,
|
||||
width: 200,
|
||||
height: 200,
|
||||
width: Math.round(200 * k),
|
||||
height: Math.round(200 * k),
|
||||
isOverlapping: false
|
||||
}
|
||||
const next = [...stickers, newSticker]
|
||||
@@ -265,7 +284,14 @@ export default function DIYPage() {
|
||||
const touch = e.touches[0]
|
||||
const next = stickers.map(s => {
|
||||
if (s.id !== activeStickerId) return s
|
||||
return { ...s, x: touch.clientX - startPos.x, y: touch.clientY - startPos.y }
|
||||
// 问题1 修正:坐标钳制在画布内,杜绝负坐标与拖出画布(碰撞盒 = x/y + 显示宽高)
|
||||
const maxX = Math.max(0, category.mask.width - s.width * s.scale)
|
||||
const maxY = Math.max(0, category.mask.height - s.height * s.scale)
|
||||
return {
|
||||
...s,
|
||||
x: Math.min(Math.max(touch.clientX - startPos.x, 0), maxX),
|
||||
y: Math.min(Math.max(touch.clientY - startPos.y, 0), maxY)
|
||||
}
|
||||
})
|
||||
const checked = checkOverlap(next)
|
||||
setStickers(checked)
|
||||
@@ -284,7 +310,16 @@ export default function DIYPage() {
|
||||
const handleScale = (id: string, delta: number) => {
|
||||
const next = stickers.map(s => {
|
||||
if (s.id !== id) return s
|
||||
return { ...s, scale: Math.max(0.3, Math.min(3, s.scale + delta)) }
|
||||
const scale = Math.max(0.3, Math.min(3, s.scale + delta))
|
||||
// 问题1 修正:缩放后把位置钳回画布内
|
||||
const maxX = Math.max(0, category.mask.width - s.width * scale)
|
||||
const maxY = Math.max(0, category.mask.height - s.height * scale)
|
||||
return {
|
||||
...s,
|
||||
scale,
|
||||
x: Math.min(Math.max(s.x, 0), maxX),
|
||||
y: Math.min(Math.max(s.y, 0), maxY)
|
||||
}
|
||||
})
|
||||
const checked = checkOverlap(next)
|
||||
setStickers(checked)
|
||||
|
||||
Reference in New Issue
Block a user