// design1核心功能模块
// 注意:此代码在layui.use回调函数内部执行,不需要$(function())包装
// 全局变量已在主入口文件中定义,这里只需要初始化
$("#object_attribute").css("height", "470px");
$("#obj_list").css("height", document.body.clientHeight - 520);
$(".obj_list").css("height", $("#obj_list").height() - 32);
var mainEl = document.querySelector('.layui-fluid.main');
if (mainEl) mainEl.style.display = 'flex';
else $(".main").show();
$(".canvas_box").css("height", document.body.clientHeight - 100);
zoom = $(".canvas_bg_img").width() / 2787
$("#canvas1").attr("width", $(".canvas_box").width() / zoom);
$("#canvas1").attr("height", $(".canvas_box").height() / zoom);
$("#canvas2").attr("width", $(".canvas_box").width() / zoom);
$("#canvas2").attr("height", $(".canvas_box").height() / zoom);
// 优化性能:在创建 Fabric Canvas 之前,先设置 canvas context 的 willReadFrequently
// 注意:这需要在 Fabric.js 创建 canvas 之前执行
try {
const canvas1El = document.getElementById('canvas1');
const canvas2El = document.getElementById('canvas2');
if (canvas1El) {
// 先获取 context 并设置 willReadFrequently,这样 Fabric.js 创建时会复用这个 context
canvas1El.getContext('2d', { willReadFrequently: true });
}
if (canvas2El) {
canvas2El.getContext('2d', { willReadFrequently: true });
}
} catch (e) {
// 如果浏览器不支持 willReadFrequently,忽略错误
}
// 初始化Canvas对象
canvas1 = new fabric.Canvas('canvas1');
canvas2 = new fabric.Canvas('canvas2');
// 同步到 window 对象,确保在 eval() 加载 .jsc 文件时也能访问
window.canvas1 = canvas1;
window.canvas2 = canvas2;
fabric.Object.prototype.objectCaching = false;
ctx1 = canvas1.getSelectionContext();
ctx2 = canvas2.getSelectionContext();
is_bgi_add = false;
// 撤销/重做过程中使用的标志位,防止并发操作和误记录历史
window._isApplyingHistory = false;
// 同步到 window 对象
window.ctx1 = ctx1;
window.ctx2 = ctx2;
window.is_bgi_add = is_bgi_add;
canvas1.zoomToPoint(new fabric.Point(0, 0), 1);
canvas2.zoomToPoint(new fabric.Point(0, 0), 1);
// 初始化标尺
initRulers();
$("#source_front").width(zoom * $("#source_front").width());
$("#source_back").width(zoom * $("#source_back").width());
$(".canvas-container:eq(0)").css('transform', 'scale(' + zoom + ')')
$(".canvas-container:eq(1)").css('transform', 'scale(' + zoom + ')')
$(".canvas-container:eq(0)").css('width', 0)
$(".canvas-container:eq(1)").hide();
canvas = canvas1;
window.canvas = canvas;
fabric.Object.prototype.set({
borderColor: "#9013FE",
cornerColor: "#9013FE", //激活状态角落图标的填充颜色
cornerStrokeColor: "#9013FE", //激活状态角落图标的边框颜色
borderOpacityWhenMoving: 1,
borderScaleFactor: 6,
cornerSize: 24,
cornerStyle: "circle", //rect,circle
centeredScaling: false, //角落放大缩小是否是以图形中心为放大原点
centeredRotation: true, //旋转按钮旋转是否是左上角为圆心旋转
transparentCorners: false, //激活状态角落的图标是否透明
rotatingPointOffset: 20, //旋转距旋转体的距离
padding: 0,
});
canvas1.preserveObjectStacking = true;
canvas2.preserveObjectStacking = true;
var front_list = [];
function applyFontList(data) {
var newFontList = [];
(data || []).map(function(item) {
if (item.indexOf('"') === 0) {
newFontList.push(item.replace(/^"|"$/g, ''));
} else {
newFontList.push(item);
}
});
front_list = newFontList;
for (var i = 0; i < front_list.length; i++) {
var item = front_list[i];
$("#text_font_family").append("");
$("#circle_text_font_family").append("");
$("#out_text_font_family").append("");
$("#barcode_font_family").append("");
$("#count_font_family").append("");
}
}
if (typeof ipcRenderer !== 'undefined' && ipcRenderer) {
ipcRenderer.on('font-list', function(event, data) { applyFontList(data); });
} else if (typeof window !== 'undefined' && window.platformBridge && window.platformBridge.getSystemFonts) {
window.platformBridge.getSystemFonts().then(applyFontList);
}
function applySysLan(data) {
let lang = localStorage.getItem("lang");
if (lang) {
s_lan = lang;
// 同步到全局作用域(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.s_lan = s_lan;
}
if (typeof global !== 'undefined') {
global.s_lan = s_lan;
}
langua_ge(lang);
$("#language_select").val(lang);
return;
}
switch (data) {
case 'zh-CN':
s_lan = "zh";
// 同步到全局作用域(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.s_lan = s_lan;
}
if (typeof global !== 'undefined') {
global.s_lan = s_lan;
}
langua_ge("zh");
$("#language_select").val("zh");
localStorage.setItem("lang", "zh");
break;
case 'zh':
s_lan = "zh";
// 同步到全局作用域(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.s_lan = s_lan;
}
if (typeof global !== 'undefined') {
global.s_lan = s_lan;
}
langua_ge("zh");
$("#language_select").val("zh");
localStorage.setItem("lang", "zh");
break;
case 'zh-TW':
case 'ozh':
s_lan = "ozh";
// 同步到全局作用域(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.s_lan = s_lan;
}
if (typeof global !== 'undefined') {
global.s_lan = s_lan;
}
langua_ge("ozh");
$("#language_select").val("ozh");
localStorage.setItem("lang", "ozh");
break;
case 'en':
s_lan = "en";
// 同步到全局作用域(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.s_lan = s_lan;
}
if (typeof global !== 'undefined') {
global.s_lan = s_lan;
}
langua_ge("en");
$("#language_select").val("en");
localStorage.setItem("lang", "en");
break;
case 'en-AU':
s_lan = "en";
// 同步到全局作用域(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.s_lan = s_lan;
}
if (typeof global !== 'undefined') {
global.s_lan = s_lan;
}
langua_ge("en");
$("#language_select").val("en");
localStorage.setItem("lang", "en");
break;
case 'en-CA':
s_lan = "en";
// 同步到全局作用域(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.s_lan = s_lan;
}
if (typeof global !== 'undefined') {
global.s_lan = s_lan;
}
langua_ge("en");
$("#language_select").val("en");
localStorage.setItem("lang", "en");
break;
case 'en-GB':
s_lan = "en";
// 同步到全局作用域(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.s_lan = s_lan;
}
if (typeof global !== 'undefined') {
global.s_lan = s_lan;
}
langua_ge("en");
$("#language_select").val("en");
localStorage.setItem("lang", "en");
break;
case 'en-NZ':
s_lan = "en";
// 同步到全局作用域(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.s_lan = s_lan;
}
if (typeof global !== 'undefined') {
global.s_lan = s_lan;
}
langua_ge("en");
$("#language_select").val("en");
localStorage.setItem("lang", "en");
break;
case 'en-US':
s_lan = "en";
// 同步到全局作用域(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.s_lan = s_lan;
}
if (typeof global !== 'undefined') {
global.s_lan = s_lan;
}
langua_ge("en");
$("#language_select").val("en");
localStorage.setItem("lang", "en");
break;
case 'en-ZA':
s_lan = "en";
// 同步到全局作用域(用于 .jsc 文件加载)
if (typeof window !== 'undefined') {
window.s_lan = s_lan;
}
if (typeof global !== 'undefined') {
global.s_lan = s_lan;
}
langua_ge("en");
$("#language_select").val("en");
localStorage.setItem("lang", "en");
break;
}
}
if (typeof ipcRenderer !== 'undefined' && ipcRenderer) {
ipcRenderer.on('sys-lan', function(event, data) { applySysLan(data); });
} else if (typeof window !== 'undefined' && window.platformBridge && window.platformBridge.getLocale) {
applySysLan(window.platformBridge.getLocale());
}
function onCloseConfirm() {
layer.confirm(language_str("whetherSave"), {
btn: [language_str("save"), language_str("noSave"), language_str("cancel")]
, btn3: function (index, layero) {}
}, function (index, layero) {
if (typeof window.output === 'function') {
window.output(function() {
if (ipcRenderer) ipcRenderer.send('run-close');
else if (window.platformBridge && window.platformBridge.runClose) window.platformBridge.runClose();
});
}
}, function (index) {
if (ipcRenderer) ipcRenderer.send('run-close');
else if (window.platformBridge && window.platformBridge.runClose) window.platformBridge.runClose();
});
}
if (typeof ipcRenderer !== 'undefined' && ipcRenderer) {
ipcRenderer.on('close', function(event, message) { onCloseConfirm(); });
} else if (typeof window !== 'undefined' && window.platformBridge && window.platformBridge.onClose) {
window.platformBridge.onClose(onCloseConfirm);
}
addBackground();//添加背景 白色卡片
initAligningGuidelines(canvas1);
initAligningGuidelines(canvas2);
//canvas.setZoom(0.5)
//recordObjs1.push(JSON.stringify(objs1));
//recordJson1.push(canvas1.toJSON(["selectable","hoverable","hoverCursor","text","fontStyle","fontWeight","underline"]));
//recordObjs2.push(JSON.stringify(objs2));
//recordJson2.push(canvas2.toJSON(["selectable","hoverable","hoverCursor","text","fontStyle","fontWeight","underline"]));
canvas.renderAll();//重新渲染画布
// 立即启动事件初始化(必须在 slider 初始化之前)
initCanvasEvents();
var zoomSlider = slider.render({
elem: '#zoomSlide', //绑定元素
min: 25,
max: 500,
value: 100,
change(val) {
canvas.zoomToPoint(
new fabric.Point(0, 0),
val / 100
);
// zoom = val / 100;
//$(".canvas-container").css("transform","scale(" + val / 100 + ")")
}
});
// ===========================================================
// Slider 滑块初始化
// ===========================================================
var circle_text_size = slider.render({
elem: '#circle_text_size',
min: 10, max: 120,
change: function (value) {
if (canvas.getActiveObject()) {
canvas.getActiveObject().set("fontSize", value);
canvas.renderAll();
}
}
});
var circle_text_diameter = slider.render({
elem: '#circle_text_diameter',
min: 500, max: 4000,
change: function (value) {
if (canvas.getActiveObject()) {
canvas.getActiveObject().set("diameter", value);
canvas.renderAll();
}
}
});
var out_pic_op = slider.render({
elem: '#out_pic_op',
change: function (value) {
if (canvas.getActiveObject()) {
canvas.getActiveObject().set('opacity', (100 - value) / 100);
canvas.renderAll();
}
}
});
var pic_op = slider.render({
elem: '#pic_op',
change: function (value) {
if (canvas.getActiveObject()) {
canvas.getActiveObject().set("opacity", (100 - value) / 100);
canvas.renderAll();
}
}
});
var rect_op = slider.render({
elem: '#rect_op',
change: function (value) {
if (canvas.getActiveObject()) {
canvas.getActiveObject().set("opacity", (100 - value) / 100);
canvas.renderAll();
}
}
});
var circle_op = slider.render({
elem: '#circle_op',
change: function (value) {
if (canvas.getActiveObject()) {
canvas.getActiveObject().set("opacity", (100 - value) / 100);
canvas.renderAll();
}
}
});
window.rotate = function (id) {
let angle = $(`#${id}`).attr("angle") - 0;
angle += 90;
$(`#${id}`).css("transform", `rotate(${angle}deg)`);
$(`#${id}`).attr("angle", angle);
}
function soonPlaceBgOnCanvas(image, canvasSelector) {
var cw = $(canvasSelector).width() || (document.querySelector(canvasSelector) && document.querySelector(canvasSelector).clientWidth) || 800;
var ch = $(canvasSelector).height() || (document.querySelector(canvasSelector) && document.querySelector(canvasSelector).clientHeight) || 600;
image.left = (cw - image.width * image.get("scaleX")) / 2;
image.top = (ch - image.height * image.get("scaleY")) / 2;
image.selectable = false;
image.hoverable = false;
image.hoverCursor = "default";
}
function soonOpenPendingDesignFile() {
var file = typeof window.soonResolveOpenFileKey === 'function'
? window.soonResolveOpenFileKey(GetFile)
: (GetFile().get('file') || '');
if (file && file != 'empty') {
if (typeof window.soonConsumeOpenMeta === 'function') {
window.soonConsumeOpenMeta(file);
}
window.openFile(file);
}
}
function addBackground() {
if (is_bgi_add || window.is_bgi_add) return;
var loadBg = typeof window.soonFabricImageFromAsset === 'function'
? window.soonFabricImageFromAsset
: null;
var whenReady = typeof window.soonRunWhenCanvasReady === 'function'
? window.soonRunWhenCanvasReady
: function (_sel, fn) { fn(); };
function finishBack(backImg) {
if (backImg) {
backImg.objectCaching = true;
soonPlaceBgOnCanvas(backImg, '#canvas2');
background_image2 = backImg;
window.background_image2 = backImg;
canvas2.add(backImg);
canvas2.renderAll();
recordObjs2.push(JSON.stringify(objs2));
recordJson2.push(canvas2.toJSON(TO_JSON_PROPERTIES));
}
is_bgi_add = true;
window.is_bgi_add = true;
soonOpenPendingDesignFile();
}
function startLoad() {
if (!loadBg) return;
loadBg('bg_front_1.png', function (frontImg) {
if (!frontImg) return;
frontImg.objectCaching = true;
frontImg.scale(1, 1);
soonPlaceBgOnCanvas(frontImg, '#canvas1');
background_image1 = frontImg;
background_image = frontImg;
window.background_image1 = frontImg;
window.background_image = frontImg;
canvas.add(frontImg);
canvas.renderAll();
recordObjs1.push(JSON.stringify(objs1));
recordJson1.push(canvas1.toJSON(TO_JSON_PROPERTIES));
loadBg('bg_back.png', finishBack, function () { loadBg('bg_back.png', finishBack, null, 2, true); }, 2, true);
}, function () {
setTimeout(startLoad, 200);
}, 2, true);
}
whenReady('#canvas1', startLoad);
}
// 将 updateControls 附加到 window 对象,确保在 eval() 加载 .jsc 文件时也能访问
window.updateControls = function updateControls() {
// 使用 window.canvas 和 window.background_image 作为后备,确保在 eval() 执行时也能访问
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"))//未锁定
}
};
// 向后兼容
function updateControls() {
return window.updateControls();
}
function selectObject(target, index) {
updateControls();
$("#base_control").show();
//$("#text_x").val((target.left - background_image.left).toFixed(1));
//$("#text_y").val((target.top - background_image.top).toFixed(1));
//$("#text_w").val(parseFloat(target.get("scaleX") * target.get("width")).toFixed(1));
//$("#text_h").val(parseFloat(target.get("scaleY") * target.get("height")).toFixed(1));
//$("#text_r").val(target.get("angle").toFixed(0));
}
function addPic(pointer) {
pre_add_image.left = pointer.x;
pre_add_image.top = pointer.y;
canvas.add(pre_add_image);
objs.push({ type: 1, black: false });
canvas.renderAll();
updateList();
window.recordState();
//OpenDialog();
//function OpenDialog()
//{
// dialog.showOpenDialog({
// title: "请选择图片",
// buttonLabel: "确认",
// filters: [
// { name: 'Image File Type', extensions: ['png', 'jpg'] },
// ]
// }).then(result => {
// if(result.canceled)return;
// //console.log(result.filePaths)
// fabric.Image.fromURL(result.filePaths[0], function(image) {
// image.left = pointer.x;
// image.top = pointer.y;
//
// canvas.add(image);
// objs.push({type: 1});
// canvas.renderAll();
// updateList();
// window.recordState();
// } );
// }).catch(err => {
// console.log(err)
// })
//}
}
function selectPic(target, index) {
//透明度
$("#pic_control").show();
$("#set_bg").show();
let activeObj = canvas.getActiveObject();
if (typeof pic_op !== 'undefined' && pic_op.setValue) {
pic_op.setValue(100 - (activeObj.get("opacity") * 100));
} else {
$("#pic_op").next().children(".layui-slider-bar").css("width", (1 - activeObj.get("opacity")) * 100 + "%");
$("#pic_op").next().children(".layui-slider-handle").css("left", (1 - activeObj.get("opacity")) * 100 + "%");
}
let idx = getIndex(canvas.getActiveObject());
// $("#pic_black").prop("checked", objs[idx-1].black ? 'checked' : '');
$("#out_pic_control").hide();
$("#text_control").hide();
$("#circle_text_control").hide();
$("#out_text_control").hide();
$("#rect_control").hide();
$("#circle_control").hide();
$("#line_control").hide();
$("#counter_control").hide();
$("#qrcode_Controll").hide();
$("#barcode_controll").hide();
}
function addOutPic(pointer) {
fabric.Image.fromURL(soonAsset('outpic_extra.png'), function (image) {
let width = canvas.getWidth();
let height = canvas.getHeight();
image.left = pointer.x;
image.top = pointer.y;
image.opacity = 1;
//image.on("selected",function(){//test well
// console.log(222);
//});
image.setSrc(image.toDataURL(), function (image) {
canvas.add(image);
objs.push({ type: 2, name: resName("OUT_PIC_"), black: false });
canvas.renderAll();
updateList();
window.recordState();
});
});
}
function selectOutPic(target, index) {
//字段名
$("#out_pic_control").show();
if (typeof out_pic_op !== 'undefined' && out_pic_op.setValue) {
out_pic_op.setValue(100 - (canvas.getActiveObject().get("opacity") * 100));
} else {
$("#out_pic_op").next().children(".layui-slider-bar").css("width", (1 - canvas.getActiveObject().get("opacity")) * 100 + "%");
$("#out_pic_op").next().children(".layui-slider-handle").css("left", (1 - canvas.getActiveObject().get("opacity")) * 100 + "%");
}
let idx = getIndex(canvas.getActiveObject());
$("#out_pic_field_name").val(objs[idx - 1].name);
// $("#out_pic_black").prop("checked", objs[idx-1].black ? 'checked' : '');
$("#pic_control").hide();
$("#set_bg").hide();
$("#text_control").hide();
$("#circle_text_control").hide();
$("#out_text_control").hide();
$("#rect_control").hide();
$("#circle_control").hide();
$("#line_control").hide();
$("#counter_control").hide();
$("#qrcode_Controll").hide();
$("#barcode_controll").hide();
}
function addText(pointer) {
let text = new fabric.Text('TEXT', {//源:文本
left: pointer.x,
top: pointer.y,
fill: "#000000",
textBackgroundColor: "",
fontStyle: "normal",
fontWeight: "normal",
fontSize: 100,
underline: false,
linethrough: false,
fontFamily: 'Arial'
});
text.setControlVisible("ml", false);
text.setControlVisible("mt", false);
text.setControlVisible("mr", false);
text.setControlVisible("mb", false);
canvas.add(text);
objs.push({ type: 3, black: false });
canvas.renderAll();
updateList();
window.recordState();
}
function selectText(target, index) {
//console.log(canvas.getActiveObject().get("fontFamily"));
$("#text_control").show();
$("#text_color").val(canvas.getActiveObject().get("fill"));
$("#text_back_color").val(canvas.getActiveObject().get("textBackgroundColor") == "" ? '#ffffff' : canvas.getActiveObject().get("textBackgroundColor"));
let val = parseFloat(canvas.getActiveObject().get("fontSize")) * 72 / dpi
if (val % 0.5 !== 0) val = Math.round(val * 2) / 2
$("#text_size").val(val);
$("#text_text").val(canvas.getActiveObject().get("text"));
$("#text_font_family").val(canvas.getActiveObject().get("fontFamily"));
if (canvas.getActiveObject().get("underline") == true) {
$("#text_underline").addClass("ui-radio-acitve")
} else {
$("#text_underline").removeClass("ui-radio-acitve")
}
if (canvas.getActiveObject().get("fontWeight") == "bold") {
$("#text_bold").addClass("ui-radio-acitve")
} else {
$("#text_bold").removeClass("ui-radio-acitve")
}
if (canvas.getActiveObject().get("fontStyle") == "italic") {
$("#text_italics").addClass("ui-radio-acitve")
} else {
$("#text_italics").removeClass("ui-radio-acitve")
}
if (canvas.getActiveObject().get("linethrough") == true) {
$("#text_linethrough").addClass("ui-radio-acitve")
} else {
$("#text_linethrough").removeClass("ui-radio-acitve")
}
$("#circle_text_control").hide();
$("#pic_control").hide();
$("#set_bg").hide();
$("#out_pic_control").hide();
$("#out_text_control").hide();
$("#rect_control").hide();
$("#circle_control").hide();
$("#line_control").hide();
$("#counter_control").hide();
$("#qrcode_Controll").hide();
$("#barcode_controll").hide();
}
function addCircleText(pointer) {
let distance = getDisdance(pointer.x, pointer.y, canvas.width / 2, canvas.height / 2)
let angleDeg = getDeg(pointer)
let text = new fabric.CurvedText('Circle TEXT', {//源:圆形文本
left: pointer.x,
top: pointer.y,
fill: "#000000",
textBackgroundColor: "",
fontStyle: "normal",
fontWeight: "normal",
diameter: distance * 2,
fontSize: 100,
underline: false,
linethrough: false,
lockScalingX: true,
lockScalingY: true,
fontFamily: 'Arial',
originX: 'center',
// originY: 'center',
angle: angleDeg,
flipped: pointer.y > canvas.height / 2 ? true : false
});
// distance = getDisdance(pointer.x+text.width/2, pointer.y, canvas.width/2,canvas.height/2)
// text.set({diameter: distance*2})
text.setControlVisible("ml", false);
text.setControlVisible("mt", false);
text.setControlVisible("mr", false);
text.setControlVisible("mb", false);
canvas.add(text);
objs.push({ type: 11, black: false });
canvas.renderAll();
updateList();
window.recordState();
}
function selectCircleText() {
// 检查是否有选中对象
if (!canvas || !canvas.getActiveObject()) return;
let idx = getIndex(canvas.getActiveObject());
$("#circle_text_control").show();
$("#circle_text_color").val(canvas.getActiveObject().get("fill"));
$("#circle_text_back_color").val(canvas.getActiveObject().get("textBackgroundColor") == "" ? '#ffffff' : canvas.getActiveObject().get("textBackgroundColor"));
// 检查 circle_text_size 是否存在且有 setValue 方法
if (typeof circle_text_size !== 'undefined' && circle_text_size && typeof circle_text_size.setValue === 'function') {
circle_text_size.setValue(canvas.getActiveObject().get("fontSize") - 10);
} else {
$("#circle_text_size").next().children(".layui-slider-bar").css("width", ((canvas.getActiveObject().get("fontSize") - 10 - 10) / (120 - 10)) * 100 + "%");
$("#circle_text_size").next().children(".layui-slider-handle").css("left", ((canvas.getActiveObject().get("fontSize") - 10 - 10) / (120 - 10)) * 100 + "%");
}
// 检查 circle_text_diameter 是否存在且有 setValue 方法
if (typeof circle_text_diameter !== 'undefined' && circle_text_diameter && typeof circle_text_diameter.setValue === 'function') {
circle_text_diameter.setValue(canvas.getActiveObject().get("diameter") - 500);
} else {
$("#circle_text_diameter").next().children(".layui-slider-bar").css("width", ((canvas.getActiveObject().get("diameter") - 500 - 500) / (4000 - 500)) * 100 + "%");
$("#circle_text_diameter").next().children(".layui-slider-handle").css("left", ((canvas.getActiveObject().get("diameter") - 500 - 500) / (4000 - 500)) * 100 + "%");
}
$("#circle_text_center").prop("checked", objs[idx - 1].circleCenter ? 'checked' : '');
$("#circle_text_text").val(canvas.getActiveObject().get("text"));
$("#circle_text_font_family").val(canvas.getActiveObject().get("fontFamily"));
if (canvas.getActiveObject().get("underline") == true) {
$("#circle_text_underline").addClass("ui-radio-acitve")
} else {
$("#circle_text_underline").removeClass("ui-radio-acitve")
}
if (canvas.getActiveObject().get("fontWeight") == "bold") {
$("#circle_text_bold").addClass("ui-radio-acitve")
} else {
$("#circle_text_bold").removeClass("ui-radio-acitve")
}
if (canvas.getActiveObject().get("fontStyle") == "italic") {
$("#circle_text_italics").addClass("ui-radio-acitve")
} else {
$("#circle_text_italics").removeClass("ui-radio-acitve")
}
if (canvas.getActiveObject().get("linethrough") == true) {
$("#circle_text_linethrough").addClass("ui-radio-acitve")
} else {
$("#circle_text_linethrough").removeClass("ui-radio-acitve")
}
$("#pic_control").hide();
$("#set_bg").hide();
$("#rotate").hide();
$("#out_pic_control").hide();
$("#text_control").hide();
$("#out_text_control").hide();
$("#rect_control").hide();
$("#circle_control").hide();
$("#line_control").hide();
$("#counter_control").hide();
$("#qrcode_Controll").hide();
$("#barcode_controll").hide();
}
function addOutText(pointer) {
//MERGE_TEXT_1
let text = new fabric.Text("MERGE TEXT", {//源:合成文本
left: pointer.x,
top: pointer.y,
fill: "#000000",
fontStyle: "normal",
fontWeight: "normal",
fontSize: 100,
textBackgroundColor: "",
underline: false,
linethrough: false,
fontFamily: 'Arial',
textAlign: 'center'
});
//text.on({
// 'scaling': function(e) {
// var obj = this,
// w = obj.width * obj.scaleX,
// h = obj.height * obj.scaleY;
//
// obj.set({
// 'height' : h,
// 'width' : w,
// 'scaleX' : 1,
// 'scaleY' : 1
// });
// }
//});
text.setControlVisible("ml", false);
text.setControlVisible("mt", false);
text.setControlVisible("mr", false);
text.setControlVisible("mb", false);
canvas.add(text);
objs.push({ type: 4, name: resName("OUT_TEXT_"), exceed: false, autoWrap: false, fixSize: false, black: false, align: 'center' });
canvas.renderAll();
updateList();
window.recordState();
}
function selectOutText(target, index) {
//color
//size
const align = canvas.getActiveObject().get('textAlign')
if (align === 'left') {
$('#out_left_alignment').parent().addClass('tool1')
} else if (align === 'right') {
$('#out_right_alignment').parent().addClass('tool1')
} else {
$('#out_center_alignment').parent().addClass('tool1')
}
$("#out_text_control").show();
$("#out_text_color").val(canvas.getActiveObject().get("fill"));
$("#out_text_text").val(canvas.getActiveObject().get("text"));
let val = parseFloat(canvas.getActiveObject().get("fontSize")) * 72 / dpi
if (val % 0.5 !== 0) val = Math.round(val * 2) / 2
$("#out_text_size").val(val);
$("#out_text_back_color").val(canvas.getActiveObject().get("textBackgroundColor") == "" ? '#ffffff' : canvas.getActiveObject().get("textBackgroundColor"));
let idx = getIndex(canvas.getActiveObject());
$("#out_text_field_name").val(objs[idx - 1].name);
$("#out_text_font_family").val(canvas.getActiveObject().get("fontFamily"));
$("#exceed").prop("checked", objs[idx - 1].exceed ? 'checked' : '');
$("#autoWrap").prop("checked", objs[idx - 1].autoWrap ? 'checked' : '');
$("#fixSize").prop("checked", objs[idx - 1].fixSize ? 'checked' : '');
if (canvas.getActiveObject().get("underline") == true) {
$("#out_text_underline").addClass("ui-radio-acitve")
} else {
$("#out_text_underline").removeClass("ui-radio-acitve")
}
if (canvas.getActiveObject().get("fontWeight") == "bold") {
$("#out_text_bold").addClass("ui-radio-acitve")
} else {
$("#out_text_bold").removeClass("ui-radio-acitve")
}
if (canvas.getActiveObject().get("fontStyle") == "italic") {
$("#out_text_italics").addClass("ui-radio-acitve")
} else {
$("#out_text_italics").removeClass("ui-radio-acitve")
}
if (canvas.getActiveObject().get("linethrough") == true) {
$("#out_text_linethrough").addClass("ui-radio-acitve")
} else {
$("#out_text_linethrough").removeClass("ui-radio-acitve")
}
$("#pic_control").hide();
$("#set_bg").hide();
$("#out_pic_control").hide();
$("#text_control").hide();
$("#circle_text_control").hide();
$("#rect_control").hide();
$("#circle_control").hide();
$("#line_control").hide();
$("#counter_control").hide();
$("#qrcode_Controll").hide();
$("#barcode_controll").hide();
}
function addRect(pointer) {
let rect = new fabric.Rect({
left: pointer.x,
top: pointer.y,
fill: '',
stroke: "#ff0000",
strokeWidth: 10,
width: 300,
height: 300
});
canvas.add(rect);
objs.push({ type: 5, black: false });
canvas.renderAll();
updateList();
window.recordState();
}
function selectRect(target, index) {
//color
$("#rect_control").show();
$("#rect_color").val(canvas.getActiveObject().get("fill") == "" ? "#ffffff" : canvas.getActiveObject().get("fill"));
$("#rect_stroke").val(canvas.getActiveObject().get("stroke") == "" ? "#ffffff" : canvas.getActiveObject().get("stroke"));
$("#rect_stroke_width").val(canvas.getActiveObject().get("strokeWidth"));
$("#rect_radius").val(canvas.getActiveObject().get("rx"));
if (typeof rect_op !== 'undefined' && rect_op.setValue) {
rect_op.setValue(100 - (canvas.getActiveObject().get("opacity") * 100));
} else {
$("#rect_op").next().children(".layui-slider-bar").css("width", (1 - canvas.getActiveObject().get("opacity")) * 100 + "%");
$("#rect_op").next().children(".layui-slider-handle").css("left", (1 - canvas.getActiveObject().get("opacity")) * 100 + "%");
}
let a = canvas.getActiveObject().getCoords();
$("#pic_control").hide();
$("#set_bg").hide();
$("#out_pic_control").hide();
$("#text_control").hide();
$("#circle_text_control").hide();
$("#out_text_control").hide();
$("#circle_control").hide();
$("#line_control").hide();
$("#counter_control").hide();
$("#qrcode_Controll").hide();
$("#barcode_controll").hide();
}
function addCircle(pointer) {
let circle = new fabric.Circle({
left: pointer.x,
top: pointer.y,
fill: '',
stroke: '#ff0000',
strokeWidth: 10,
radius: 150,
strokeUniform: true,
});
canvas.add(circle);
objs.push({ type: 6, black: false });
canvas.renderAll();
updateList();
window.recordState();
}
function selectCircle(target, index) {
//border-color
//color
$("#circle_control").show();
$("#circle_color").val(canvas.getActiveObject().get("fill") == "" ? "#ffffff" : canvas.getActiveObject().get("fill"));
$("#circle_stroke").val(canvas.getActiveObject().get("stroke") == "" ? "#ffffff" : canvas.getActiveObject().get("stroke"));
$("#circle_stroke_width").val(canvas.getActiveObject().get("strokeWidth"));
if (typeof circle_op !== 'undefined' && circle_op.setValue) {
circle_op.setValue(100 - (canvas.getActiveObject().get("opacity") * 100));
} else {
$("#circle_op").next().children(".layui-slider-bar").css("width", (1 - canvas.getActiveObject().get("opacity")) * 100 + "%");
$("#circle_op").next().children(".layui-slider-handle").css("left", (1 - canvas.getActiveObject().get("opacity")) * 100 + "%");
}
$("#pic_control").hide();
$("#set_bg").hide();
$("#out_pic_control").hide();
$("#text_control").hide();
$("#circle_text_control").hide();
$("#out_text_control").hide();
$("#rect_control").hide();
$("#line_control").hide();
$("#counter_control").hide();
$("#qrcode_Controll").hide();
$("#barcode_controll").hide();
}
function addLine(pointer) {
let line = new fabric.Line([100, 200, 400, 200], {
left: pointer.x,
top: pointer.y,
stroke: '#ff0000',
strokeWidth: 10,
strokeDashArray: [0, 0],
});
line.setControlVisible("tl", false);
line.setControlVisible("tr", false);
line.setControlVisible("br", false);
line.setControlVisible("bl", false);
line.setControlVisible("mt", false);
line.setControlVisible("mb", false);
canvas.add(line);
objs.push({ type: 7, black: false });
canvas.renderAll();
updateList();
window.recordState();
}
function selectLine(target, index) {
//color
//weight
$("#line_control").show();
let idx = getIndex(canvas.getActiveObject());
$("#line_color").val(canvas.getActiveObject().get("stroke"));
$("#line_dist").val(canvas.getActiveObject().get("strokeDashArray")[0]);
$("#text_h").val(canvas.getActiveObject().get("strokeWidth"))
$("#pic_control").hide();
$("#set_bg").hide();
$("#out_pic_control").hide();
$("#text_control").hide();
$("#circle_text_control").hide();
$("#out_text_control").hide();
$("#rect_control").hide();
$("#circle_control").hide();
$("#counter_control").hide();
$("#qrcode_Controll").hide();
$("#barcode_controll").hide();
}
function addQrCode(pointer) {
let qr = jrQrcode.getQrBase64('https://www.cardsoon.com', { padding: 0 });
fabric.Image.fromURL(qr, function (image) {
image.left = pointer.x;
image.top = pointer.y;
image.scale(2.4, 2.4)
canvas.add(image);
objs.push({ type: 8, name: resName("QR_CODE_"), color: "#000000", val: "https://www.cardsoon.com", black: false });
canvas.renderAll();
updateList();
window.recordState();
});
}
function selectQrCode(target, index) {
//字段名
//background-color
//color
$("#qrcode_Controll").show();
let idx = getIndex(canvas.getActiveObject());
$("#qrcode_field_name").val(objs[idx - 1].name);
$("#qrcode_color").val(objs[idx - 1].color);
$("#qrcode_val").val(objs[idx - 1].val);
$("#line_control").hide();
$("#pic_control").hide();
$("#set_bg").hide();
$("#out_pic_control").hide();
$("#text_control").hide();
$("#circle_text_control").hide();
$("#out_text_control").hide();
$("#rect_control").hide();
$("#circle_control").hide();
$("#counter_control").hide();
$("#barcode_controll").hide();
}
function addBarCode(pointer) {
JsBarcode("#barcode", "123456789", { margin: 0, lineColor: "#000000", fontSize: 18, font: "Arial" });
let barcode = document.getElementById('barcode');
let bar = barcode.toDataURL("image/png");
fabric.Image.fromURL(bar, function (image) {
image.left = pointer.x;
image.top = pointer.y;
image.scale(2.4, 2.4)
canvas.add(image);
objs.push({ type: 9, name: resName("BAR_CODE_"), val: "123456789", color: "#000000", fontSize: 18, font: "Arial", show: false, black: false });//show是取消文字显示
canvas.renderAll();
updateList();
window.recordState();
});
}
function selectBarCode(target, index) {
//字段名
//background-color
//color
$("#barcode_controll").show();
let idx = getIndex(canvas.getActiveObject());
$("#barcode_field_name").val(objs[idx - 1].name);
$("#barcode_font_family").val(objs[idx - 1].font);
let val = parseFloat(objs[idx - 1].fontSize) * 72 / dpi
if (val % 0.5 !== 0) val = Math.round(val * 2) / 2
$("#barcode_size").val(val);
$("#barcode_val").val(objs[idx - 1].val);
$("#barcode_show").prop("checked", objs[idx - 1].show ? 'checked' : '');
$("#line_control").hide();
$("#pic_control").hide();
$("#set_bg").hide();
$("#out_pic_control").hide();
$("#text_control").hide();
$("#circle_text_control").hide();
$("#out_text_control").hide();
$("#rect_control").hide();
$("#circle_control").hide();
$("#counter_control").hide();
$("#qrcode_Controll").hide();
}
function addCounter(pointer) {
let text = new fabric.Text('0', {
left: pointer.x,
top: pointer.y,
fontSize: 100,
fill: "#000000",
});
canvas.add(text);
objs.push({ type: 10, name: resName("COUNTER_"), start: 0, add: 1, black: false });
canvas.renderAll();
updateList();
window.recordState();
}
function selectCounter(target, index) {
//起始
//终止
//增量
$("#counter_control").show();
let idx = getIndex(canvas.getActiveObject());
$("#counter_start").val(objs[idx - 1].start);
$("#counter_add").val(objs[idx - 1].add);
$("#counter_color").val(canvas.getActiveObject().get("fill"));
$("#count_font_family").val(canvas.getActiveObject().get("fontFamily"));
let val = parseFloat(canvas.getActiveObject().get("fontSize")) * 72 / dpi
if (val % 0.5 !== 0) val = Math.round(val * 2) / 2
$("#count_size").val(val);
$("#line_control").hide();
$("#pic_control").hide();
$("#set_bg").hide();
$("#out_pic_control").hide();
$("#text_control").hide();
$("#circle_text_control").hide();
$("#out_text_control").hide();
$("#rect_control").hide();
$("#circle_control").hide();
$("#qrcode_Controll").hide();
$("#barcode_controll").hide();
}
// 将 updateList 附加到 window 对象,确保全局可访问
window.updateList = function updateList() {
let str = "";
let i = 0;
// 定义行样式:Flex布局,两端对齐,相对定位防止溢出
const rowStyle = "display:flex; justify-content:space-between; align-items:center; height:32px; padding:0 5px; cursor:pointer; border-bottom:1px solid #444; color:#ccc; font-size:12px; position:relative;";
// 定义左侧内容样式
const leftStyle = "display:flex; align-items:center; overflow:hidden; white-space:nowrap; max-width:180px;";
// 定义序号样式:靠右,有左边框
const indexStyle = "min-width:24px; text-align:center; padding-left:5px; color:#666; border-left:1px solid #555;";
for (let item of objs) {
let displayIndex = i + 1; // 序号底层为1
// 图标逻辑
let iconName = "rect.svg";
switch (item.type) {
case 1: iconName = "images.svg"; break;
case 2: iconName = "images_add.svg"; break;
case 3: iconName = "text.svg"; break;
case 4: iconName = "text2.svg"; break;
case 5: iconName = "rect.svg"; break;
case 6: iconName = "round.svg"; break;
case 7: iconName = "line.svg"; break;
case 8: iconName = "qrcode.svg"; break;
case 9: iconName = "barcode.svg"; break;
case 10: iconName = "counter.svg"; break;
case 11: iconName = "text3.svg"; break;
}
// 名称逻辑
let nameText = item.name ? item.name :
(item.type === 3 ? "TEXT_" + displayIndex :
(item.type === 1 ? "IMG_" + displayIndex : "OBJ_" + displayIndex));
// 检查锁定状态(通过lockMovementX判断,因为锁定时会设置所有lock属性)
// 注意:索引0是背景图,objs数组是从下标0开始存第1个对象的,所以是 i+1
let isLocked = false;
if (canvas.getObjects()[i + 1]) {
let canvasObj = canvas.getObjects()[i + 1];
isLocked = canvasObj.get('lockMovementX') === true;
}
// 锁定状态图标
const lockIcon = isLocked ?
`
` :
`
`;
str = `