fix(web): design1/2 缩略图与 design2 设为背景交互修复

- design1:预览/最近文件缩略图按 background 边界截取,去掉多余白盘
- design2:设为背景贴齐 1012x648 卡框,保存/打开保留用户背景 src
- design2:列表可选中锁定对象并加载完整属性,缩略图叠加 front_bg 模板
- design2:固定卡框锚点,避免选中背景时标尺/蒙版随属性面板漂移

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
24kycj
2026-06-25 19:26:17 +08:00
parent 0f196bdec8
commit 784cacf259
7 changed files with 746 additions and 183 deletions
+77 -16
View File
@@ -77,9 +77,66 @@
return soonEnsureSoonExt(soonSessionSlug(keyOrName));
}
/** 缩略图截取框:对齐 background_image 设计边界(design1 光盘外接方 / design2 卡面) */
function soonResolveSavePreviewCrop(canvas) {
if (!canvas) return null;
var bg = null;
if (typeof window !== 'undefined' && window.canvas1 === canvas && window.background_image1) {
bg = window.background_image1;
}
if (!bg && typeof canvas.getObjects === 'function') {
var objs = canvas.getObjects();
if (objs.length && objs[0] && objs[0].type === 'image') bg = objs[0];
}
if (!bg || !bg.width || !bg.height) return null;
var sx = bg.scaleX == null ? 1 : bg.scaleX;
var sy = bg.scaleY == null ? 1 : bg.scaleY;
var cw = canvas.width || 0;
var ch = canvas.height || 0;
var w;
var h;
var left = bg.left;
var top = bg.top;
w = bg.width * sx;
h = bg.height * sy;
if (!(w > 0 && h > 0)) return null;
if (cw > 0 && ch > 0) {
var x1 = Math.max(0, left);
var y1 = Math.max(0, top);
var x2 = Math.min(cw, left + w);
var y2 = Math.min(ch, top + h);
w = x2 - x1;
h = y2 - y1;
if (w <= 0 || h <= 0) return null;
left = x1;
top = y1;
}
return { left: left, top: top, width: w, height: h };
}
function soonIsDesign2SaveCanvas(canvas) {
return !!(typeof window.soonBuildDesign2SavePreviewPic === 'function'
&& window.canvas1 && canvas === window.canvas1);
}
function soonIsDesign1SaveCanvas(canvas) {
return !!(typeof window.soonBuildDesign1SavePreviewPic === 'function'
&& window.canvas1 && canvas === window.canvas1);
}
function soonBuildSavePreviewPic(canvas) {
var THUMB_MAX = 102400;
if (!canvas || typeof canvas.getObjects !== 'function') return '';
if (soonIsDesign2SaveCanvas(canvas)) {
var d2Pic = window.soonBuildDesign2SavePreviewPic(canvas);
if (d2Pic) return d2Pic;
return '';
}
if (soonIsDesign1SaveCanvas(canvas)) {
var d1Pic = window.soonBuildDesign1SavePreviewPic(canvas);
if (d1Pic) return d1Pic;
return '';
}
var hidden = [];
canvas.getObjects().forEach(function (obj) {
if (obj.isGuideLine) {
@@ -88,24 +145,28 @@
}
});
if (hidden.length) canvas.renderAll();
window._soonSkipDesign1CdMask = true;
var mult = 0.18;
var crop = soonResolveSavePreviewCrop(canvas);
var mult = crop ? 0.28 : 0.18;
var quality = 0.72;
var url = '';
try {
for (var i = 0; i < 3; i++) {
try {
var candidate = canvas.toDataURL({ format: 'jpeg', quality: quality, multiplier: mult });
if (candidate && candidate.indexOf('data:image/') === 0 && candidate.length <= THUMB_MAX) {
url = candidate;
break;
}
} catch (e) { /* ignore */ }
quality -= 0.18;
mult -= 0.04;
}
} finally {
window._soonSkipDesign1CdMask = false;
for (var i = 0; i < 3; i++) {
try {
var opts = { format: 'jpeg', quality: quality, multiplier: mult };
if (crop) {
opts.left = crop.left;
opts.top = crop.top;
opts.width = crop.width;
opts.height = crop.height;
}
canvas.renderAll();
var candidate = canvas.toDataURL(opts);
if (candidate && candidate.indexOf('data:image/') === 0 && candidate.length <= THUMB_MAX) {
url = candidate;
break;
}
} catch (e) { /* ignore */ }
quality -= 0.18;
mult -= 0.04;
}
hidden.forEach(function (obj) { obj.visible = true; });
canvas.renderAll();
+50 -21
View File
@@ -448,21 +448,47 @@ function addBackground() {
}
// 将 updateControls 附加到 window 对象,确保在 eval() 加载 .jsc 文件时也能访问
window.updateControls = function updateControls() {
// 使用 window.canvas 和 window.background_image 作为后备,确保在 eval() 执行时也能访问
window._soonSyncingFontControls = false;
function soonFontSizeUiVal(fontSizePx) {
var d = window.dpi || 600;
var uiVal = parseFloat(fontSizePx) * 72 / d;
if (uiVal % 0.5 !== 0) uiVal = Math.round(uiVal * 2) / 2;
return uiVal;
}
function soonSyncActiveFontSizeInput(activeObj, currentCanvas) {
if (!activeObj) return;
var idx = getIndex(activeObj, currentCanvas);
if (idx <= 0) return;
var objData = (window.objs || objs)[idx - 1];
if (!objData) return;
var uiVal = soonFontSizeUiVal(activeObj.get('fontSize'));
if (objData.type === 3) $("#text_size").val(uiVal);
else if (objData.type === 4) $("#out_text_size").val(uiVal);
else if (objData.type === 10) $("#count_size").val(uiVal);
}
window.updateControls = function () {
const currentCanvas = window.canvas || canvas;
const currentBackgroundImage = window.background_image || background_image;
if (!currentCanvas || !currentCanvas.getActiveObject()) return;
$("#text_r").val(currentCanvas.getActiveObject().get("angle").toFixed(0));
$("#text_x").val((currentCanvas.getActiveObject().get("left") - currentBackgroundImage.left).toFixed(0));
$("#text_y").val((currentCanvas.getActiveObject().get("top") - currentBackgroundImage.top).toFixed(0));
$("#text_h").val((currentCanvas.getActiveObject().get("scaleY") * currentCanvas.getActiveObject().get("height")).toFixed(0));
$("#text_w").val((currentCanvas.getActiveObject().get("scaleX") * currentCanvas.getActiveObject().get("width")).toFixed(0));
// 根据锁定状态显示图标(使用lockMovementX判断,因为锁定时会设置所有lock属性)
if (currentCanvas.getActiveObject().get("lockMovementX")) {
$("#lock_img").attr("src", soonAsset("lock20.png"))//已锁定
} else {
$("#lock_img").attr("src", soonAsset("unlock20.png"))//未锁定
const activeObj = currentCanvas.getActiveObject();
window._soonSyncingFontControls = true;
try {
$("#text_r").val(activeObj.get("angle").toFixed(0));
$("#text_x").val((activeObj.get("left") - currentBackgroundImage.left).toFixed(0));
$("#text_y").val((activeObj.get("top") - currentBackgroundImage.top).toFixed(0));
$("#text_h").val((activeObj.get("scaleY") * activeObj.get("height")).toFixed(0));
$("#text_w").val((activeObj.get("scaleX") * activeObj.get("width")).toFixed(0));
soonSyncActiveFontSizeInput(activeObj, currentCanvas);
if (activeObj.get("lockMovementX")) {
$("#lock_img").attr("src", soonAsset("lock20.png"));
} else {
$("#lock_img").attr("src", soonAsset("unlock20.png"));
}
} finally {
window._soonSyncingFontControls = false;
}
};
// 向后兼容
@@ -1786,18 +1812,21 @@ function initCanvasEvents() {
return;
}
let target = event.target;
var modAction = event.action || (event.transform && event.transform.action);
if ([3, 4, 10].includes(objData.type)) {
target.fontSize = (target.fontSize * target.scaleX).toFixed(0);
target.scaleX = 1; target.scaleY = 1;
if ([3, 4, 10].includes(objData.type) && modAction === 'scale') {
target.set({
fontSize: Math.round(target.fontSize * (target.scaleX || 1)),
scaleX: 1,
scaleY: 1,
});
target._clearCache();
if (objData.type == 3) $("#text_size").val(target.fontSize);
if (objData.type == 4) $("#out_text_size").val(target.fontSize);
if (objData.type == 10) $("#count_size").val(target.fontSize);
currentCanvas.renderAll();
} else if (objData.type == 5) {
target.width *= target.scaleX; target.height *= target.scaleY;
target.scaleX = 1; target.scaleY = 1;
} else if (objData.type == 5 && modAction === 'scale') {
target.width *= target.scaleX || 1;
target.height *= target.scaleY || 1;
target.scaleX = 1;
target.scaleY = 1;
}
window.recordState();
// 更新对象列表以同步锁状态
+67 -6
View File
@@ -52,6 +52,62 @@ async function saveImageAsPNG(buffer) {
}
}
/** 从画布像素截取光盘外接方(含 after:render 圆外暗蒙版),与编辑器所见一致 */
function soonDesign1CaptureCanvasRect(canvas, outW, outH, format, quality) {
var bg = window.background_image1 || window.background_image;
if (!canvas || !bg) return '';
var srcEl = canvas.lowerCanvasEl;
if (!srcEl || !srcEl.getContext) return '';
var sx = bg.scaleX == null ? 1 : bg.scaleX;
var sy = bg.scaleY == null ? 1 : bg.scaleY;
var sw = bg.width * sx;
var sh = bg.height * sy;
var retina = (typeof canvas.getRetinaScaling === 'function') ? canvas.getRetinaScaling() : 1;
outW = outW || Math.round(sw);
outH = outH || Math.round(sh);
var tmp = document.createElement('canvas');
tmp.width = outW;
tmp.height = outH;
var tctx = tmp.getContext('2d');
tctx.drawImage(
srcEl,
bg.left * retina, bg.top * retina, sw * retina, sh * retina,
0, 0, outW, outH
);
if (format === 'jpeg') return tmp.toDataURL('image/jpeg', quality == null ? 0.75 : quality);
return tmp.toDataURL('image/png');
}
function soonBuildDesign1SavePreviewPic(canvas) {
var THUMB_MAX = 102400;
var c1 = window.canvas1;
if (!canvas || (c1 && canvas !== c1)) return '';
var hidden = [];
canvas.getObjects().forEach(function (obj) {
if (obj.isGuideLine) {
hidden.push(obj);
obj.visible = false;
}
});
if (canvas.discardActiveObject) canvas.discardActiveObject();
canvas.renderAll();
var url = '';
var sizes = [320, 280, 240, 200];
var quals = [0.82, 0.68, 0.52, 0.38];
for (var i = 0; i < sizes.length; i++) {
url = soonDesign1CaptureCanvasRect(canvas, sizes[i], sizes[i], 'jpeg', quals[i]);
if (url && url.indexOf('data:image/') === 0 && url.length <= THUMB_MAX) break;
url = '';
}
hidden.forEach(function (obj) { obj.visible = true; });
canvas.renderAll();
if (canvas.requestRenderAll) canvas.requestRenderAll();
return url;
}
window.soonBuildDesign1SavePreviewPic = soonBuildDesign1SavePreviewPic;
window.display_func = function display_func(img1, img2, img3) {
$("#base_control").hide();
$("#line_control").hide();
@@ -217,13 +273,18 @@ window.display_func = function display_func(img1, img2, img3) {
left: all_left
});
g3.push(img1);
let url3 = new fabric.Group(g3).toDataURL({
height: 2787,
width: 2787,
top: all_top,
left: all_left
var hiddenForPreview = [];
canvas1.getObjects().forEach(function (o) {
if (o.isGuideLine) {
hiddenForPreview.push(o);
o.visible = false;
}
});
canvas1.discardActiveObject();
canvas1.renderAll();
let url3 = soonDesign1CaptureCanvasRect(canvas1, 2787, 2787, 'png');
hiddenForPreview.forEach(function (o) { o.visible = true; });
canvas1.renderAll();
let url5 = new fabric.Group(g5).toDataURL({
height: 2787,
width: 2787,
+8
View File
@@ -1453,6 +1453,7 @@ $("#new").click(function () {
// ===========================================================
$("#text_y").bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
if (!canvas.getActiveObject()) return;
if ($("#text_y").val() == "") {
$("#text_y").val(0)
@@ -1466,6 +1467,7 @@ $("#text_y").bind('input propertychange', function () {
window.recordState();
})
$("#text_x").bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
if (!canvas.getActiveObject()) return;
if ($("#text_x").val() == "") {
$("#text_x").val(0)
@@ -1479,6 +1481,7 @@ $("#text_x").bind('input propertychange', function () {
window.recordState();
})
$("#text_w").bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
if (!canvas.getActiveObject()) return;
let val = "0";
if ($("#text_w").val() != "") {
@@ -1497,6 +1500,7 @@ $("#text_w").bind('input propertychange', function () {
window.recordState();
})
$("#text_h").bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
if (!canvas.getActiveObject()) return;
let idx = getIndex(canvas.getActiveObject());
if (idx <= 0 || !objs[idx - 1]) return;
@@ -1523,6 +1527,7 @@ $("#text_h").bind('input propertychange', function () {
window.recordState();
})
$("#text_r").bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
if (!canvas.getActiveObject()) return;
if ($("#text_r").val() == "") {
$("#text_r").val("0")
@@ -1619,6 +1624,7 @@ $("#text_back_color").bind('input propertychange', function () {
window.recordState();
})
$("#text_size").bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
let val = 1
if (parseFloat($("#text_size").val())) {
val = parseFloat($("#text_size").val())
@@ -1671,6 +1677,7 @@ $("#out_text_back_color").bind('input propertychange', function () {
window.recordState();
})
$("#out_text_size").bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
let val = 1
if (parseFloat($("#out_text_size").val())) {
val = parseFloat($("#out_text_size").val())
@@ -1786,6 +1793,7 @@ $("#counter_color").bind('input propertychange', function () {
window.recordState();
})
$("#count_size").bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
let val = 1
if (parseFloat($("#count_size").val())) {
val = parseFloat($("#count_size").val())
+371 -61
View File
@@ -165,7 +165,13 @@ function initRulers() {
// background_image在画布坐标系中的left值,需要转换到标尺坐标系
// 画布从标尺的marginOffset位置开始,所以:标尺0点 = marginOffset + background_image.left (如果存在)
let originX = marginOffset;
if (typeof background_image !== 'undefined' && background_image) {
var rulerSide = ($('#back_side').hasClass('ui-button-active')) ? canvas2 : canvas1;
var anchorX = typeof soonDesign2GetFrameAnchor === 'function'
? soonDesign2GetFrameAnchor(rulerSide)
: null;
if (anchorX) {
originX = marginOffset + anchorX.left;
} else if (typeof background_image !== 'undefined' && background_image) {
originX = marginOffset + background_image.left;
}
const startX = 0;
@@ -257,7 +263,13 @@ function initRulers() {
// background_image在画布坐标系中的top值,需要转换到标尺坐标系
// 画布从标尺的marginOffset + rulerHeightOffset位置开始,所以:标尺0点 = marginOffset + rulerHeightOffset + background_image.top (如果存在)
let originY = marginOffset + rulerHeightOffset;
if (typeof background_image !== 'undefined' && background_image) {
var rulerSideY = ($('#back_side').hasClass('ui-button-active')) ? canvas2 : canvas1;
var anchorY = typeof soonDesign2GetFrameAnchor === 'function'
? soonDesign2GetFrameAnchor(rulerSideY)
: null;
if (anchorY) {
originY = marginOffset + rulerHeightOffset + anchorY.top;
} else if (typeof background_image !== 'undefined' && background_image) {
originY = marginOffset + rulerHeightOffset + background_image.top;
}
const startY = 0;
@@ -355,15 +367,19 @@ function initRulers() {
}, 100);
});
// 监听画布缩放/渲染变化,仅用于重绘标尺
// 辅助线交给 Fabric 自己渲染,否则会出现“重影 / 变两三根”的现象
canvas1.off('after:render');
canvas2.off('after:render');
canvas1.on('after:render', function () {
drawHorizontalRuler();
drawVerticalRuler();
soonDesign2DrawCardMask(canvas1, ctx1, document.getElementById('source_front'));
soonDesign2DrawTemplateOverlay(canvas1, ctx1, document.getElementById('source_front'));
});
canvas2.on('after:render', function () {
drawHorizontalRuler();
drawVerticalRuler();
soonDesign2DrawCardMask(canvas2, ctx2, document.getElementById('source_back'));
soonDesign2DrawTemplateOverlay(canvas2, ctx2, document.getElementById('source_back'));
});
// --- 辅助线功能 (参考 design1) ---
@@ -568,6 +584,221 @@ function soonDesign2ScaleBgSources() {
}
}
function soonDesign2BgOverlayMetrics(imgEl) {
if (!imgEl || !imgEl.complete || imgEl.naturalWidth <= 0) return null;
var z = zoom || window.zoom || 0.5;
var w = parseFloat(imgEl.style.width);
if (!w || w <= 0) w = imgEl.naturalWidth * z;
var h = parseFloat(imgEl.style.height);
if (!h || h <= 0) h = imgEl.naturalHeight * z;
return { w: w, h: h };
}
/** 卡面区域:与 background_image 对齐(1012×648),fallback 模板线框 */
function soonDesign2ResolveCardFrame(fabricCanvas, imgEl) {
if (!fabricCanvas) return null;
var metaList = (fabricCanvas === canvas2) ? (window.objs2 || objs2) : (window.objs1 || objs1);
if (soonDesign2IsUserBgMeta(metaList)) {
var anchor = soonDesign2GetFrameAnchor(fabricCanvas);
var card = soonDesign2CardSize();
if (anchor) {
return { left: anchor.left, top: anchor.top, width: card.w, height: card.h };
}
}
var bg = (fabricCanvas === canvas1) ? background_image1 : background_image2;
if (bg && bg.width) {
var sx = bg.scaleX == null ? 1 : bg.scaleX;
var sy = bg.scaleY == null ? 1 : bg.scaleY;
return {
left: bg.left,
top: bg.top,
width: bg.width * sx,
height: bg.height * sy
};
}
var cw = fabricCanvas.width || 1012;
var ch = fabricCanvas.height || 648;
if (imgEl) {
var metrics = soonDesign2BgOverlayMetrics(imgEl);
if (metrics) {
return {
left: (cw - metrics.w) / 2,
top: (ch - metrics.h) / 2,
width: metrics.w,
height: metrics.h
};
}
}
return { left: 0, top: 0, width: cw, height: ch };
}
function soonDesign2CardSize() {
return { w: 1012, h: 648 };
}
function soonDesign2IsUserBgMeta(metaList) {
return !!(metaList && metaList.length > 0 && metaList[0] && metaList[0].type === 1);
}
function soonDesign2SyncFrameAnchor(fabricCanvas, frame) {
if (!frame) return;
var pt = { left: frame.left, top: frame.top };
if (fabricCanvas === canvas2) {
window.soonDesign2FrameAnchor2 = pt;
} else {
window.soonDesign2FrameAnchor1 = pt;
}
var active = window.canvas || canvas;
if (!active || fabricCanvas === active) {
window.soonDesign2FrameAnchor = pt;
}
}
function soonDesign2GetFrameAnchor(fabricCanvas) {
if (fabricCanvas === canvas2 && window.soonDesign2FrameAnchor2) {
return window.soonDesign2FrameAnchor2;
}
if (window.soonDesign2FrameAnchor1) {
return window.soonDesign2FrameAnchor1;
}
return window.soonDesign2FrameAnchor || null;
}
/** 用户设为背景的对象:坐标系锚点,属性面板不应再移动它 */
function soonDesign2ActiveIsAnchorBg() {
var c = window.canvas || canvas;
if (!c) return false;
var ao = c.getActiveObject();
if (!ao) return false;
var meta = (c === canvas2) ? (window.objs2 || objs2) : (window.objs1 || objs1);
if (c === (window.canvas || canvas)) {
meta = window.objs || objs || meta;
}
if (!soonDesign2IsUserBgMeta(meta)) return false;
var bg = (c === canvas2) ? (window.background_image2 || background_image2) : (window.background_image1 || background_image1);
return ao === bg;
}
function soonDesign2FrameOrigin(fabricCanvas) {
var frame = soonDesign2ResolveCardFrame(fabricCanvas, null);
if (frame) return frame;
var card = soonDesign2CardSize();
var cw = (fabricCanvas && fabricCanvas.width) || card.w;
var ch = (fabricCanvas && fabricCanvas.height) || card.h;
return { left: (cw - card.w) / 2, top: (ch - card.h) / 2, width: card.w, height: card.h };
}
/** 用户图铺满卡面框(1012×648),与蒙版/线框同源坐标 */
function soonDesign2SnapImageToCardFrame(img, fabricCanvas, frame) {
if (!img || !img.width) return frame || soonDesign2FrameOrigin(fabricCanvas);
frame = frame || soonDesign2FrameOrigin(fabricCanvas);
var card = soonDesign2CardSize();
img.set({
originX: 'left',
originY: 'top',
scaleX: card.w / img.width,
scaleY: card.h / img.height,
left: frame.left,
top: frame.top
});
img.setCoords();
soonDesign2SyncFrameAnchor(fabricCanvas, frame);
return frame;
}
function soonDesign2ApplyUserBgAsCanvas0(userImg, fabricCanvas, oldBg) {
if (!userImg || !fabricCanvas) return;
if (oldBg && oldBg !== userImg) {
fabricCanvas.remove(oldBg);
}
fabricCanvas.sendToBack(userImg);
if (fabricCanvas === canvas2) {
background_image2 = userImg;
window.background_image2 = userImg;
} else {
background_image1 = userImg;
window.background_image1 = userImg;
}
var activeCanvas = window.canvas || canvas;
if (fabricCanvas === activeCanvas) {
background_image = userImg;
window.background_image = userImg;
}
}
function soonDesign2LockBgObject(bgObj) {
if (!bgObj) return;
bgObj.set({
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
lockSkewingX: true,
lockSkewingY: true,
selectable: false,
evented: false,
hoverCursor: 'default'
});
}
/** 打开旧文件:去掉残留模板层,用户背景独占 canvas[0] 并贴齐卡框 */
function soonDesign2NormalizeUserBg(fabricCanvas, metaList) {
if (!soonDesign2IsUserBgMeta(metaList) || !fabricCanvas) return null;
var all = fabricCanvas.getObjects().filter(function (o) { return !o.isGuideLine; });
if (!all.length) return null;
var frame = soonDesign2FrameOrigin(fabricCanvas);
var userBg = all[0];
if (all.length > 1) {
fabricCanvas.remove(all[0]);
userBg = fabricCanvas.getObjects().filter(function (o) { return !o.isGuideLine; })[0];
}
if (!userBg) return null;
soonDesign2SnapImageToCardFrame(userBg, fabricCanvas, frame);
soonDesign2ApplyUserBgAsCanvas0(userBg, fabricCanvas, null);
soonDesign2LockBgObject(userBg);
return userBg;
}
window.soonDesign2CardSize = soonDesign2CardSize;
window.soonDesign2IsUserBgMeta = soonDesign2IsUserBgMeta;
window.soonDesign2SyncFrameAnchor = soonDesign2SyncFrameAnchor;
window.soonDesign2GetFrameAnchor = soonDesign2GetFrameAnchor;
window.soonDesign2ActiveIsAnchorBg = soonDesign2ActiveIsAnchorBg;
window.soonDesign2FrameOrigin = soonDesign2FrameOrigin;
window.soonDesign2SnapImageToCardFrame = soonDesign2SnapImageToCardFrame;
window.soonDesign2ApplyUserBgAsCanvas0 = soonDesign2ApplyUserBgAsCanvas0;
window.soonDesign2LockBgObject = soonDesign2LockBgObject;
window.soonDesign2NormalizeUserBg = soonDesign2NormalizeUserBg;
function soonDesign2DrawCardMask(fabricCanvas, ctx, imgEl) {
if (window._soonSkipDesign2CardMask || !fabricCanvas || !ctx) return;
var frame = soonDesign2ResolveCardFrame(fabricCanvas, imgEl);
if (!frame) return;
var left = frame.left;
var top = frame.top;
var cardW = frame.width;
var cardH = frame.height;
ctx.save();
ctx.beginPath();
ctx.rect(0, 0, fabricCanvas.width, fabricCanvas.height);
ctx.moveTo(left + cardW, top);
ctx.lineTo(left, top);
ctx.lineTo(left, top + cardH);
ctx.lineTo(left + cardW, top + cardH);
ctx.closePath();
ctx.fillStyle = 'rgba(0, 0, 0, 0.9)';
ctx.fill('evenodd');
ctx.restore();
}
function soonDesign2DrawTemplateOverlay(fabricCanvas, ctx, imgEl) {
if (!window.is_bgi_add || !fabricCanvas || !ctx || !imgEl) return;
var frame = soonDesign2ResolveCardFrame(fabricCanvas, imgEl);
if (!frame) return;
ctx.drawImage(imgEl, frame.left, frame.top, frame.width, frame.height);
}
function soonDesign2PrepareBgSources(done) {
var sf = document.getElementById('source_front');
var sb = document.getElementById('source_back');
@@ -647,21 +878,47 @@ canvas2.preserveObjectStacking = true
// 对象选择和属性更新函数
// ==========================================
// 将 updateControls 附加到 window 对象,确保在 eval() 加载 .jsc 文件时也能访问
window.updateControls = function updateControls() {
// 使用 window.canvas 和 window.background_image 作为后备,确保在 eval() 执行时也能访问
window._soonSyncingFontControls = false;
function soonFontSizeUiVal(fontSizePx) {
var d = window.dpi || 300;
var uiVal = parseFloat(fontSizePx) * 72 / d;
if (uiVal % 0.5 !== 0) uiVal = Math.round(uiVal * 2) / 2;
return uiVal;
}
function soonSyncActiveFontSizeInput(activeObj, currentCanvas) {
if (!activeObj || !currentCanvas) return;
var idx = getIndex(activeObj, currentCanvas);
if (idx <= 0) return;
var objData = (currentCanvas === canvas1 ? objs1 : objs2)[idx - 1];
if (!objData) return;
var uiVal = soonFontSizeUiVal(activeObj.get('fontSize'));
if (objData.type === 3) $("#text_size").val(uiVal);
else if (objData.type === 4) $("#out_text_size").val(uiVal);
else if (objData.type === 10) $("#count_size").val(uiVal);
}
window.updateControls = function () {
const currentCanvas = window.canvas || canvas;
const currentBackgroundImage = window.background_image || background_image;
if (!currentCanvas || !currentCanvas.getActiveObject()) return;
$("#text_r").val(currentCanvas.getActiveObject().get("angle").toFixed(0));
$("#text_x").val((currentCanvas.getActiveObject().get("left") - currentBackgroundImage.left).toFixed(0));
$("#text_y").val((currentCanvas.getActiveObject().get("top") - currentBackgroundImage.top).toFixed(0));
$("#text_h").val((currentCanvas.getActiveObject().get("scaleY") * currentCanvas.getActiveObject().get("height")).toFixed(0));
$("#text_w").val((currentCanvas.getActiveObject().get("scaleX") * currentCanvas.getActiveObject().get("width")).toFixed(0));
// 根据锁定状态显示图标(使用lockMovementX判断,因为锁定时会设置所有lock属性)
if (currentCanvas.getActiveObject().get("lockMovementX")) {
$("#lock_img").attr("src", soonAsset("lock20.png"))//已锁定
} else {
$("#lock_img").attr("src", soonAsset("unlock20.png"))//未锁定
const activeObj = currentCanvas.getActiveObject();
window._soonSyncingFontControls = true;
try {
$("#text_r").val(activeObj.get("angle").toFixed(0));
$("#text_x").val((activeObj.get("left") - currentBackgroundImage.left).toFixed(0));
$("#text_y").val((activeObj.get("top") - currentBackgroundImage.top).toFixed(0));
$("#text_h").val((activeObj.get("scaleY") * activeObj.get("height")).toFixed(0));
$("#text_w").val((activeObj.get("scaleX") * activeObj.get("width")).toFixed(0));
soonSyncActiveFontSizeInput(activeObj, currentCanvas);
if (activeObj.get("lockMovementX")) {
$("#lock_img").attr("src", soonAsset("lock20.png"));
} else {
$("#lock_img").attr("src", soonAsset("unlock20.png"));
}
} finally {
window._soonSyncingFontControls = false;
}
};
// 向后兼容
@@ -1052,8 +1309,10 @@ function handleObjectSelected(e) {
return;
}
// 3. 获取索引
let i = getIndex(select_obj, canvas);
// 3. 解析 objs 下标(用户设为背景时在 canvas[0],不能仅用 getIndex
let metaIdx = typeof soonDesign2ResolveObjMetaIndex === 'function'
? soonDesign2ResolveObjMetaIndex(select_obj, canvas)
: (getIndex(select_obj, canvas) > 0 ? getIndex(select_obj, canvas) - 1 : -1);
// 如果不是通过对象列表选中的,且对象被锁定,则取消选中
if (!window._selectingFromList && isObjectLocked(select_obj)) {
@@ -1065,58 +1324,52 @@ function handleObjectSelected(e) {
return;
}
if (i != 0) {
// --- 选中了普通对象 ---
--i; // 转换为 objs 数组下标
// 安全检查:确保 objs[i] 存在且有 type 属性
if (objs[i] && typeof objs[i].type !== 'undefined') {
switch (objs[i].type) {
if (metaIdx >= 0) {
if (objs[metaIdx] && typeof objs[metaIdx].type !== 'undefined') {
switch (objs[metaIdx].type) {
case 1: // 图片
$("#component_type").text(language_str("img"));
selectObject(select_obj, i); selectPic(select_obj, i); break;
selectObject(select_obj, metaIdx); selectPic(select_obj, metaIdx); break;
case 2: // 合成图片
$("#component_type").text(language_str("simg"));
selectObject(select_obj, i); selectOutPic(select_obj, i); break;
selectObject(select_obj, metaIdx); selectOutPic(select_obj, metaIdx); break;
case 3: // 文本
$("#component_type").text(language_str("text"));
selectObject(select_obj, i); selectText(select_obj, i); break;
selectObject(select_obj, metaIdx); selectText(select_obj, metaIdx); break;
case 4: // 合成文本
$("#component_type").text(language_str("stext"));
selectObject(select_obj, i); selectOutText(select_obj, i); break;
selectObject(select_obj, metaIdx); selectOutText(select_obj, metaIdx); break;
case 5: // 矩形
$("#component_type").text(language_str("rect"));
selectObject(select_obj, i); selectRect(select_obj, i); break;
selectObject(select_obj, metaIdx); selectRect(select_obj, metaIdx); break;
case 6: // 圆形
$("#component_type").text(language_str("circ"));
selectObject(select_obj, i); selectCircle(select_obj, i); break;
selectObject(select_obj, metaIdx); selectCircle(select_obj, metaIdx); break;
case 7: // 直线
$("#component_type").text(language_str("line"));
selectObject(select_obj, i); selectLine(select_obj, i); break;
selectObject(select_obj, metaIdx); selectLine(select_obj, metaIdx); break;
case 8: // 二维码
$("#component_type").text(language_str("qrc"));
selectObject(select_obj, i); selectQrCode(select_obj, i); break;
selectObject(select_obj, metaIdx); selectQrCode(select_obj, metaIdx); break;
case 9: // 条形码
$("#component_type").text(language_str("barc"));
selectObject(select_obj, i); selectBarCode(select_obj, i); break;
selectObject(select_obj, metaIdx); selectBarCode(select_obj, metaIdx); break;
case 10: // 计数器
$("#component_type").text(language_str("counter"));
selectObject(select_obj, i); selectCounter(select_obj, i); break;
selectObject(select_obj, metaIdx); selectCounter(select_obj, metaIdx); break;
case 11: // 圆形文本
$("#component_type").text(language_str("ctext"));
selectObject(select_obj, i); selectCircleText(select_obj, i); break;
selectObject(select_obj, metaIdx); selectCircleText(select_obj, metaIdx); break;
}
}
// 【关键】这里传入 true
// 意思是:因为我已经是在画布上选中它了,selectObj 函数只负责把左边的条目变灰,不要再回头去 setActiveObject 了
selectObj(i, true);
selectObj(metaIdx, true);
} else {
// --- 选中了背景 ---
// --- 模板背景(canvas[0] 且不在 objs 中)---
$("#base_control, #line_control, #pic_control, #out_pic_control, #text_control, #circle_text_control, #out_text_control, #rect_control, #circle_control, #counter_control, #qrcode_Controll, #barcode_controll").hide();
selectObj(-1, true);
$("#component_type").text(language_str("bg"));
selectObj(-1, true);
}
}
@@ -1363,22 +1616,24 @@ function initCanvasEvents() {
return;
}
let target = event.target;
var modAction = event.action || (event.transform && event.transform.action);
if ([3, 4, 10].includes(objData.type)) {
target.fontSize = (target.fontSize * target.scaleX).toFixed(0);
target.scaleX = 1; target.scaleY = 1;
if ([3, 4, 10].includes(objData.type) && modAction === 'scale') {
target.set({
fontSize: Math.round(target.fontSize * (target.scaleX || 1)),
scaleX: 1,
scaleY: 1,
});
target._clearCache();
if (objData.type == 3) $("#text_size").val(target.fontSize);
if (objData.type == 4) $("#out_text_size").val(target.fontSize);
if (objData.type == 10) $("#count_size").val(target.fontSize);
currentCanvas.renderAll();
updateControls();
} else if (objData.type == 5) {
target.width *= target.scaleX; target.height *= target.scaleY;
target.scaleX = 1; target.scaleY = 1;
updateControls();
} else if (objData.type == 5 && modAction === 'scale') {
target.width *= target.scaleX || 1;
target.height *= target.scaleY || 1;
target.scaleX = 1;
target.scaleY = 1;
}
recordState();
updateControls();
// 更新对象列表以同步锁状态
if (typeof window.updateList === 'function') {
window.updateList();
@@ -1430,8 +1685,10 @@ window.updateList = function updateList() {
// 检查锁定状态(通过lockMovementX判断,因为锁定时会设置所有lock属性)
// 注意:索引0是背景图,objs数组是从下标0开始存第1个对象的,所以是 i+1
let isLocked = false;
if (currentCanvas.getObjects()[i + 1]) {
let canvasObj = currentCanvas.getObjects()[i + 1];
var canvasObj = typeof window.soonCanvasObjForListIndex === 'function'
? window.soonCanvasObjForListIndex(i)
: currentCanvas.getObjects()[i + 1];
if (canvasObj) {
isLocked = canvasObj.get('lockMovementX') === true;
}
@@ -1454,9 +1711,9 @@ window.updateList = function updateList() {
// 重新绑定点击事件(防止 updateList 后点击失效)
$(".obj_list > div").on("click", function () {
let imgId = $(this).find("img").attr("id");
let imgId = $(this).find("img[id^='obj']").attr("id");
if (imgId) {
let idx = parseInt(imgId.replace("obj", ""));
let idx = parseInt(imgId.replace("obj", ""), 10);
selectObj(idx);
}
});
@@ -1465,6 +1722,40 @@ window.updateList = function updateList() {
// 标记是否通过对象列表选中(用于区分鼠标点击和列表点击)
window._selectingFromList = false;
// 对象列表下标 → 画布对象(设为背景后 objs 与 canvas 一一对应)
function soonCanvasObjForListIndex(listIdx) {
var c = window.canvas || canvas;
var metaList = window.objs || objs;
if (!c || listIdx < 0 || listIdx >= metaList.length) return null;
var all = c.getObjects().filter(function (o) { return !o.isGuideLine; });
var bgListedInObjs = metaList.length >= all.length;
if (bgListedInObjs) {
return all[listIdx] || null;
}
for (var j = 0; j < all.length; j++) {
var o = all[j];
var ci = getIndex(o, c);
if (ci > 0 && ci - 1 === listIdx) return o;
}
return null;
}
window.soonCanvasObjForListIndex = soonCanvasObjForListIndex;
/** 画布选中对象 → objs 下标;-1 表示模板背景(不在 objs 中) */
function soonDesign2ResolveObjMetaIndex(select_obj, fabricCanvas) {
if (!select_obj || !fabricCanvas) return -1;
var metaList = fabricCanvas === canvas2 ? (window.objs2 || objs2) : (window.objs1 || objs1);
if (fabricCanvas === (window.canvas || canvas)) {
metaList = window.objs || objs || metaList;
}
if (!metaList || !metaList.length) return -1;
for (var li = 0; li < metaList.length; li++) {
if (soonCanvasObjForListIndex(li) === select_obj) return li;
}
return -1;
}
window.soonDesign2ResolveObjMetaIndex = soonDesign2ResolveObjMetaIndex;
// 将 selectObj 附加到 window 对象,确保全局可访问
window.selectObj = function selectObj(objIndices, isFromCanvas = false) {
let indicesArray = (Array.isArray(objIndices)) ? objIndices : ((typeof objIndices === 'number' && objIndices >= 0) ? [objIndices] : []);
@@ -1474,10 +1765,10 @@ window.selectObj = function selectObj(objIndices, isFromCanvas = false) {
// 遍历列表查找并高亮
$('.obj_list > div').each(function () {
let $img = $(this).find("img");
let $img = $(this).find("img[id^='obj']");
if ($img.length === 0) return;
let idIndex = parseInt($img.attr("id").replace("obj", ""));
let idIndex = parseInt($img.attr("id").replace("obj", ""), 10);
if (indicesArray.includes(idIndex)) {
$(this).css("background-color", "#6F7A84");
@@ -1491,7 +1782,7 @@ window.selectObj = function selectObj(objIndices, isFromCanvas = false) {
// 如果是点击列表,触发画布选中
if (!isFromCanvas && indicesArray.length === 1) {
let target = canvas.getObjects()[indicesArray[0] + 1];
let target = soonCanvasObjForListIndex(indicesArray[0]);
if (target) {
// 检查对象是否被锁定
let isLocked = isObjectLocked(target);
@@ -1733,6 +2024,15 @@ function soonPlaceBgOnCanvas(image, canvasSelector) {
image.selectable = false
image.hoverable = false
image.hoverCursor = 'default'
var fc = (canvasSelector === '#canvas2') ? canvas2 : canvas1;
if (fc && typeof soonDesign2SyncFrameAnchor === 'function') {
soonDesign2SyncFrameAnchor(fc, {
left: image.left,
top: image.top,
width: image.width * (image.get('scaleX') || 1),
height: image.height * (image.get('scaleY') || 1)
});
}
}
function soonOpenPendingDesignFile() {
@@ -2264,7 +2564,12 @@ var out_pic_op = slider.render({
if (canvas.getActiveObject()) {
canvas.getActiveObject().set('opacity', 1 - value / 100);
canvas.renderAll();
updateControls();
window._soonSyncingFontControls = true;
try {
updateControls();
} finally {
window._soonSyncingFontControls = false;
}
recordState();
}
}
@@ -2279,7 +2584,12 @@ var pic_op = slider.render({
if (canvas.getActiveObject()) {
canvas.getActiveObject().set('opacity', 1 - value / 100);
canvas.renderAll();
updateControls();
window._soonSyncingFontControls = true;
try {
updateControls();
} finally {
window._soonSyncingFontControls = false;
}
recordState();
}
}
+120 -7
View File
@@ -1,3 +1,99 @@
/** design2 正面预览/缩略图:1012×648 视口,与 display_func 中 url3 一致 */
function soonCollectDesign2FrontPreview(canvas, bgImage, objMetaList) {
if (!canvas || !bgImage || typeof canvas.getObjects !== 'function') return null;
var list = canvas.getObjects().filter(function (obj) { return !obj.isGuideLine; });
var g3 = [];
var all_left = 0;
var all_top = 0;
for (var i = 0; i < list.length; i++) {
var item = list[i];
var idx = getIndex(item, canvas);
var metaIdx = typeof window.soonDesign2ResolveObjMetaIndex === 'function'
? window.soonDesign2ResolveObjMetaIndex(item, canvas)
: (idx > 0 ? idx - 1 : -1);
if (metaIdx < 0 && idx !== 0) continue;
if (metaIdx >= 0 && (!objMetaList[metaIdx] || typeof objMetaList[metaIdx].type === 'undefined')) continue;
if (getCoordsMinX(bgImage.getCoords()) - getCoordsMinX(item.getCoords()) > all_left) {
all_left = -(getCoordsMinX(item.getCoords()) - getCoordsMinX(bgImage.getCoords()));
}
if (getCoordsMinY(bgImage.getCoords()) - getCoordsMinY(item.getCoords()) > all_top) {
all_top = -(getCoordsMinY(item.getCoords()) - getCoordsMinY(bgImage.getCoords()));
}
g3.push(fabric.util.object.clone(item));
}
return { g3: g3, all_left: all_left, all_top: all_top };
}
function soonExportDesign2PreviewDataUrl(g3, all_left, all_top, quality, multiplier) {
var z = (typeof zoom !== 'undefined' ? zoom : null) || window.zoom || 1;
var opts = {
height: 648,
width: 1012,
top: all_top / z,
left: all_left / z,
format: 'jpeg',
quality: quality == null ? 0.72 : quality
};
if (multiplier != null && multiplier > 0) opts.multiplier = multiplier;
return new fabric.Group(g3).toDataURL(opts);
}
/** 缩略图/预览:叠加系统卡面模板 front_bg(与编辑区 source_front 一致) */
function soonDesign2AppendTemplateOverlayToGroup(g3, canvas, bgImage) {
if (!g3 || !canvas) return false;
var sf = document.getElementById('source_front');
if (!sf || !(sf.complete && sf.naturalWidth > 0)) return false;
var frame = typeof window.soonDesign2FrameOrigin === 'function'
? window.soonDesign2FrameOrigin(canvas)
: null;
if (!frame && bgImage && bgImage.width) {
var sx = bgImage.scaleX == null ? 1 : bgImage.scaleX;
var sy = bgImage.scaleY == null ? 1 : bgImage.scaleY;
frame = { left: bgImage.left, top: bgImage.top, width: bgImage.width * sx, height: bgImage.height * sy };
}
if (!frame || !(frame.width > 0 && frame.height > 0)) return false;
g3.push(new fabric.Image(sf, {
left: frame.left,
top: frame.top,
originX: 'left',
originY: 'top',
scaleX: frame.width / sf.naturalWidth,
scaleY: frame.height / sf.naturalHeight
}));
return true;
}
function soonBuildDesign2SavePreviewPic(canvas) {
var THUMB_MAX = 102400;
var c1 = window.canvas1;
if (!canvas || (c1 && canvas !== c1)) return '';
var bg = window.background_image1 || window.background_image;
var meta = window.objs1;
if (!bg || !Array.isArray(meta)) return '';
if (typeof canvas.renderAll === 'function') canvas.renderAll();
var pack = soonCollectDesign2FrontPreview(canvas, bg, meta);
if (!pack || !pack.g3.length) return '';
soonDesign2AppendTemplateOverlayToGroup(pack.g3, canvas, bg);
var quality = 0.72;
var mult = 0.55;
var url = '';
for (var i = 0; i < 4; i++) {
try {
url = soonExportDesign2PreviewDataUrl(pack.g3, pack.all_left, pack.all_top, quality, mult);
if (url && url.indexOf('data:image/') === 0 && url.length <= THUMB_MAX) return url;
} catch (e) { /* ignore */ }
quality -= 0.16;
mult -= 0.08;
if (mult < 0.28) mult = 0.28;
}
try {
url = soonExportDesign2PreviewDataUrl(pack.g3, pack.all_left, pack.all_top, 0.32, 0.28);
if (url && url.indexOf('data:image/') === 0) return url;
} catch (e2) { /* ignore */ }
return '';
}
window.soonBuildDesign2SavePreviewPic = soonBuildDesign2SavePreviewPic;
window.display_func = function display_func(img1, img2, img3) {
$('#base_control').hide()
$('#line_control').hide()
@@ -1046,9 +1142,11 @@ window.cleanupSrcFields = function cleanupSrcFields(jsonObjects, objsArray) {
let obj = jsonObjects[i];
// 只处理 fabric.Image 对象且有 src 字段的
if (obj && obj.type === 'image' && obj.src) {
// 背景图片(索引 0- 删除 src
// 模板背景(索引 0删 src;用户设为背景时 fo[0] 为 type 1,须保留
if (i === 0) {
delete obj.src;
if (!(objsArray[0] && objsArray[0].type === 1)) {
delete obj.src;
}
}
// 其他对象,通过 objs 数组判断类型
else if (i - 1 < objsArray.length) {
@@ -1338,6 +1436,8 @@ window.openFile = function open(file, jAlready) {
return;
}
openAs.name = file;
const fo = j.fo || []
const bo = j.bo || []
var left = background_image.left
let top = background_image.top
let new_left = j.f.objects[0].left
@@ -1350,18 +1450,25 @@ window.openFile = function open(file, jAlready) {
o.left = o.left - new_left + left
o.top = o.top - new_top + top
}
// 如果背景图片没有src,从路径恢复(因为保存时删除了src以减小文件大小)
if (j.f.objects[0] && !j.f.objects[0].src) {
var isUserBgFront = typeof window.soonDesign2IsUserBgMeta === 'function'
? window.soonDesign2IsUserBgMeta(fo)
: (fo[0] && fo[0].type === 1)
var isUserBgBack = typeof window.soonDesign2IsUserBgMeta === 'function'
? window.soonDesign2IsUserBgMeta(bo)
: (bo[0] && bo[0].type === 1)
if (j.f.objects[0] && !j.f.objects[0].src && !isUserBgFront) {
j.f.objects[0].src = soonAsset('bg_front_2.png')
} else if (j.f.objects[0] && !j.f.objects[0].src && isUserBgFront && j.f.objects.length > 1) {
j.f.objects[0].src = soonAsset('bg_front_2.png')
}
if (j.b.objects[0] && !j.b.objects[0].src) {
if (j.b.objects[0] && !j.b.objects[0].src && !isUserBgBack) {
j.b.objects[0].src = soonAsset('bg_back_2.png')
} else if (j.b.objects[0] && !j.b.objects[0].src && isUserBgBack && j.b.objects.length > 1) {
j.b.objects[0].src = soonAsset('bg_back_2.png')
}
// 为二维码和条形码对象创建临时的 src(Fabric.js 需要 src 来创建 Image 对象)
// 加载完成后会重新生成,所以这里只需要一个占位符
const fo = j.fo || []
const bo = j.bo || []
const placeholder = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='
// 为正面二维码、条形码和合成图片创建临时 src
@@ -1492,6 +1599,9 @@ window.openFile = function open(file, jAlready) {
}
canvas1.loadFromJSON(j.f, function () {
if (typeof window.soonDesign2NormalizeUserBg === 'function') {
window.soonDesign2NormalizeUserBg(canvas1, fo);
}
// 加载后解锁所有对象(背景除外)
if (typeof window.unlockAllObjects === 'function') {
window.unlockAllObjects(canvas1);
@@ -1508,6 +1618,9 @@ window.openFile = function open(file, jAlready) {
saveInitialState()
})
canvas2.loadFromJSON(j.b, function () {
if (typeof window.soonDesign2NormalizeUserBg === 'function') {
window.soonDesign2NormalizeUserBg(canvas2, bo);
}
// 加载后解锁所有对象(背景除外)
if (typeof window.unlockAllObjects === 'function') {
window.unlockAllObjects(canvas2);
+53 -72
View File
@@ -365,6 +365,8 @@ $('#version_change').click(function () {
if (typeof window.soonDesign2ScaleBgSources === 'function') {
window.soonDesign2ScaleBgSources()
}
canvas1.requestRenderAll()
canvas2.requestRenderAll()
}
sf.onerror = sf.onload
sf.src = soonAsset('front_bg' + bg_version + '_2.png')
@@ -785,62 +787,38 @@ $('#down_obj').click(function () {
}
})
$('#set_bg').click(function () {
//设置为背景
let obj = canvas.getActiveObject()
let idx = getIndex(canvas.getActiveObject())
const scaleX = 1012 / obj.width
const scaleY = 648 / obj.height
// 使用缩放后的实际尺寸计算位置,确保与初始背景图片位置一致
const scaledWidth = obj.width * scaleX;
const scaledHeight = obj.height * scaleY;
obj.set({
scaleX: scaleX,
scaleY: scaleY,
left: ($('#canvas1').width() - scaledWidth) / 2,
top: ($('#canvas1').height() - scaledHeight) / 2
})
$('#text_w').val(1012)
$('#text_h').val(648)
$('#text_x').val(0)
$('#text_y').val(0)
// 设为背景时,锁定所有编辑操作,并设置为不可选中
obj.set({
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
lockSkewingX: true,
lockSkewingY: true,
selectable: false,
evented: false
});
let idx = getIndex(obj)
var oldBg = background_image1 || background_image
var frame = typeof window.soonDesign2FrameOrigin === 'function'
? window.soonDesign2FrameOrigin(canvas)
: { left: oldBg.left, top: oldBg.top }
if (typeof window.soonDesign2SnapImageToCardFrame === 'function') {
window.soonDesign2SnapImageToCardFrame(obj, canvas, frame)
}
var card = typeof window.soonDesign2CardSize === 'function'
? window.soonDesign2CardSize()
: { w: 1012, h: 648 }
window._soonSyncingFontControls = true;
try {
$('#text_w').val(card.w)
$('#text_h').val(card.h)
$('#text_x').val(0)
$('#text_y').val(0)
} finally {
window._soonSyncingFontControls = false;
}
if (typeof window.soonDesign2LockBgObject === 'function') {
window.soonDesign2LockBgObject(obj)
}
$("#lock_img").attr("src", soonAsset("lock20.png"))
canvas.sendToBack(canvas.getActiveObject())
canvas.bringForward(canvas.getActiveObject())
if (typeof window.soonDesign2ApplyUserBgAsCanvas0 === 'function') {
window.soonDesign2ApplyUserBgAsCanvas0(obj, canvas, oldBg)
}
canvas.renderAll()
let objItem = objs.splice(idx - 1, 1)[0]
objs.unshift(objItem)
// 确保背景图(索引0)的锁定属性被正确设置
setTimeout(() => {
let bgObj = canvas.getObjects()[0];
if (bgObj) {
bgObj.set({
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
lockSkewingX: true,
lockSkewingY: true,
selectable: false,
evented: false
});
canvas.renderAll();
}
}, 100);
recordState()
if (typeof window.updateList === 'function') {
window.updateList();
@@ -1385,23 +1363,6 @@ function selectObject(target, index) {
$('#base_control').show()
//$("#text_x").val((target.left - background_image.left).toFixed(1));
}
function updateControls() {
// 检查是否有选中对象,如果没有则直接返回
if (!canvas || !canvas.getActiveObject()) return;
const activeObj = canvas.getActiveObject();
$('#text_r').val(activeObj.get('angle').toFixed(0))
$('#text_x').val((activeObj.get('left') - background_image.left).toFixed(0))
$('#text_y').val((activeObj.get('top') - background_image.top).toFixed(0))
$('#text_h').val((activeObj.get('scaleY') * activeObj.get('height')).toFixed(0))
$('#text_w').val((activeObj.get('scaleX') * activeObj.get('width')).toFixed(0))
// 根据锁定状态显示图标(使用lockMovementX判断,因为锁定时会设置所有lock属性)
if (activeObj.get('lockMovementX')) {
$('#lock_img').attr('src', soonAsset('lock20.png')) //已锁定
} else {
$('#lock_img').attr('src', soonAsset('unlock20.png')) //未锁定
}
}
function checkName(name) {
//检查字段名是否重复了
for (let item of objs1) {
@@ -1444,8 +1405,8 @@ function selectPic(target, index) {
let activeObj = canvas.getActiveObject();
// 检查对象是否被锁定
if (isObjectLocked(activeObj)) {
// 列表选中时允许锁定对象保持选中;画布点击仍不可选
if (!window._selectingFromList && isObjectLocked(activeObj)) {
canvas.discardActiveObject();
canvas.renderAll();
return;
@@ -2092,6 +2053,8 @@ function getCoordsMaxY(acoords) {
}
$('#text_y').bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
if (typeof window.soonDesign2ActiveIsAnchorBg === 'function' && window.soonDesign2ActiveIsAnchorBg()) return;
if ($('#text_y').val() == '') {
$('#text_y').val(0)
}
@@ -2104,6 +2067,8 @@ $('#text_y').bind('input propertychange', function () {
recordState()
})
$('#text_x').bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
if (typeof window.soonDesign2ActiveIsAnchorBg === 'function' && window.soonDesign2ActiveIsAnchorBg()) return;
if ($('#text_x').val() == '') {
$('#text_x').val(0)
}
@@ -2116,11 +2081,17 @@ $('#text_x').bind('input propertychange', function () {
recordState()
})
$('#text_w').bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
if (typeof window.soonDesign2ActiveIsAnchorBg === 'function' && window.soonDesign2ActiveIsAnchorBg()) return;
let val = '0'
if ($('#text_w').val() != '') {
val = $('#text_w').val()
}
let type = objs[getIndex(canvas.getActiveObject()) - 1].type
var metaIdx = typeof window.soonDesign2ResolveObjMetaIndex === 'function'
? window.soonDesign2ResolveObjMetaIndex(canvas.getActiveObject(), canvas)
: getIndex(canvas.getActiveObject()) - 1;
if (metaIdx < 0 || !objs[metaIdx]) return;
let type = objs[metaIdx].type
if (type == 3 || type == 4) {
canvas.getActiveObject().set('width', parseInt(val))
} else {
@@ -2131,8 +2102,13 @@ $('#text_w').bind('input propertychange', function () {
recordState()
})
$('#text_h').bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
if (typeof window.soonDesign2ActiveIsAnchorBg === 'function' && window.soonDesign2ActiveIsAnchorBg()) return;
let idx = getIndex(canvas.getActiveObject())
if (objs[idx - 1].type == 7) {
var metaIdx = typeof window.soonDesign2ResolveObjMetaIndex === 'function'
? window.soonDesign2ResolveObjMetaIndex(canvas.getActiveObject(), canvas)
: idx - 1;
if (metaIdx >= 0 && objs[metaIdx] && objs[metaIdx].type == 7) {
if ($('#text_h').val() == '') {
$('#text_h').val(canvas.getActiveObject().get('strokeWidth'))
}
@@ -2144,7 +2120,8 @@ $('#text_h').bind('input propertychange', function () {
if ($('#text_h').val() != '') {
val = $('#text_h').val()
}
let type = objs[getIndex(canvas.getActiveObject()) - 1].type
if (metaIdx < 0 || !objs[metaIdx]) return;
let type = objs[metaIdx].type
if (type == 3 || type == 4) {
canvas.getActiveObject().set('height', parseInt(val))
} else {
@@ -2155,6 +2132,7 @@ $('#text_h').bind('input propertychange', function () {
recordState()
})
$('#text_r').bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
if ($('#text_r').val() == '') {
$('#text_r').val('0')
}
@@ -2257,6 +2235,7 @@ $('#out_text_back_color').bind('input propertychange', function () {
recordState()
})
$("#text_size").bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
let val = 1
if (parseFloat($("#text_size").val())) {
val = parseFloat($("#text_size").val())
@@ -2312,6 +2291,7 @@ $('#out_text_color').bind('input propertychange', function () {
recordState()
})
$("#out_text_size").bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
let val = 1
if (parseFloat($("#out_text_size").val())) {
val = parseFloat($("#out_text_size").val())
@@ -2417,6 +2397,7 @@ $('#counter_color').bind('input propertychange', function () {
recordState()
})
$("#count_size").bind('input propertychange', function () {
if (window._soonSyncingFontControls) return;
let val = 1
if (parseFloat($("#count_size").val())) {
val = parseFloat($("#count_size").val())