Files
SoonDesign/lib/design2/core.js
T
2025-12-09 09:43:47 +08:00

2750 lines
113 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// design2核心功能模块
// 注意:此代码在layui.use回调函数内部执行
// 全局变量已在主入口文件中定义,这里只需要初始化
$('#canvas1').attr('height', document.body.clientHeight - 100)
$('#canvas2').attr('height', document.body.clientHeight - 100)
$('#object_attribute').css('height', '470px')
$('#obj_list').css('height', document.body.clientHeight - 520)
$('.obj_list').css('height', $('#obj_list').height() - 32)
$('.main').show()
$('#canvas1').attr('width', $('#canvas-div').width())
$('#canvas2').attr('width', $('#canvas-div').width())
// 初始化Canvas对象
// 优化性能:在创建 Fabric Canvas 之前,先设置 canvas context 的 willReadFrequently
try {
const canvas1El = document.getElementById('canvas1');
const canvas2El = document.getElementById('canvas2');
if (canvas1El) {
canvas1El.getContext('2d', { willReadFrequently: true });
}
if (canvas2El) {
canvas2El.getContext('2d', { willReadFrequently: true });
}
} catch (e) {
// 如果浏览器不支持 willReadFrequently,忽略错误
}
canvas1 = new fabric.Canvas('canvas1')
canvas2 = new fabric.Canvas('canvas2')
fabric.Object.prototype.objectCaching = false
ctx1 = canvas1.getSelectionContext()
ctx2 = canvas2.getSelectionContext()
is_bgi_add = false
canvas1.zoomToPoint(new fabric.Point(canvas1.width / 2, canvas1.height / 2), $('#canvas-div').width() / 1200 > 1 ? 1 : $('#canvas-div').width() / 1200)
//console.log(canvas1.width / 2, canvas1.height / 2);
//console.log($("#canvas-div").width() / 1200 > 1 ? 1 : $("#canvas-div").width() / 1200);
canvas2.zoomToPoint(new fabric.Point(canvas2.width / 2, canvas2.height / 2), $('#canvas-div').width() / 1200 > 1 ? 1 : $('#canvas-div').width() / 1200)
zoom = $('#canvas-div').width() / 1200 > 1 ? 1 : $('#canvas-div').width() / 1200
// 初始化标尺
function initRulers() {
// dpi已在主入口文件中定义为全局变量
const mmToPx = dpi / 25.4; // 1mm = 11.811px (300 DPI)
const rulerHeight = 20;
const rulerWidth = 20;
// 获取实际画布的像素尺寸(px
// design2.html 的实际画布尺寸是 1012px x 648px
const actualCanvasWidth = canvas1.width || 1012; // 实际画布宽度(px
const actualCanvasHeight = canvas1.height || 648; // 实际画布高度(px
// 获取显示区域的尺寸(包括 margin)
const canvasDiv = $('#canvas-div');
const canvasWrapper = $('.canvas-wrapper');
// 使用 canvas-wrapper 的宽度,如果没有则使用 canvas_div 的宽度
let canvasWidth = canvasWrapper.width();
let canvasHeight = canvasWrapper.height();
if (!canvasWidth || canvasWidth === 0) {
const canvas1Width = $('#canvas1').width() || canvasDiv.width() - 20;
canvasWidth = canvas1Width + 20; // 加上 margin-left: 20px
}
if (!canvasHeight || canvasHeight === 0) {
const canvas1Height = $('#canvas1').height() || canvasDiv.height() - 20;
canvasHeight = canvas1Height + 20; // 加上 margin-top: 20px
}
// 设置标尺尺寸(使用显示区域的尺寸)
$('#ruler-h').attr('width', canvasWidth).attr('height', rulerHeight);
$('#ruler-v').attr('width', rulerWidth).attr('height', canvasHeight);
$('.ruler-horizontal').css('width', canvasWidth + 'px');
$('.ruler-vertical').css('height', canvasHeight + 'px');
// 绘制水平标尺
function drawHorizontalRuler() {
const ctx = document.getElementById('ruler-h').getContext('2d', { willReadFrequently: true });
ctx.clearRect(0, 0, canvasWidth, rulerHeight);
// 背景
ctx.fillStyle = '#2C2C2C';
ctx.fillRect(0, 0, canvasWidth, rulerHeight);
// 边框
ctx.strokeStyle = '#1E1E1E';
ctx.lineWidth = 1;
ctx.strokeRect(0, 0, canvasWidth, rulerHeight);
ctx.beginPath();
ctx.moveTo(0, rulerHeight - 1);
ctx.lineTo(canvasWidth, rulerHeight - 1);
ctx.stroke();
// 刻度线
ctx.strokeStyle = '#888888';
ctx.fillStyle = '#CCCCCC';
ctx.font = '10px Arial';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
// 计算:实际画布尺寸(px)对应的物理尺寸(mm),然后根据显示区域的缩放比例计算
// 实际画布物理宽度 = actualCanvasWidth / dpi * 25.4 (mm)
// 显示区域宽度 = actualCanvasWidth * zoom (px)
// 所以:1mm 在显示区域中 = (actualCanvasWidth * zoom) / (actualCanvasWidth / dpi * 25.4) = zoom * dpi / 25.4
const pxPerMm = zoom * mmToPx; // 在显示区域中,1mm对应的像素数
const marginOffset = 20; // canvas 的 margin-left: 20px
// 标尺0点应该在background_image的左上角位置
// background_image在画布坐标系中的left值,需要转换到标尺坐标系
// 画布从标尺的marginOffset位置开始,所以:标尺0点 = marginOffset + background_image.left (如果存在)
let originX = marginOffset;
if (typeof background_image !== 'undefined' && background_image) {
originX = marginOffset + background_image.left;
}
const startX = 0;
const endX = canvasWidth;
// 绘制主要刻度(每10mm
// 从0点向左绘制负值刻度
for (let mm = -10; originX + mm * pxPerMm >= startX; mm -= 10) {
const x = originX + mm * pxPerMm;
if (x < startX) break;
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, rulerHeight);
ctx.stroke();
// 数字(负值)
ctx.fillText(mm + 'mm', x + 2, 2);
}
// 从0点向右绘制正值刻度
for (let mm = 0; originX + mm * pxPerMm <= endX; mm += 10) {
const x = originX + mm * pxPerMm;
if (x > endX) break;
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, rulerHeight);
ctx.stroke();
// 数字
ctx.fillText(mm + 'mm', x + 2, 2);
}
// 绘制次要刻度(每1mm
// 从0点向左绘制负值刻度
for (let mm = -1; originX + mm * pxPerMm >= startX; mm -= 1) {
const x = originX + mm * pxPerMm;
if (x < startX) break;
if (mm % 10 === 0) continue; // 跳过主要刻度
ctx.beginPath();
ctx.moveTo(x, rulerHeight - 8);
ctx.lineTo(x, rulerHeight);
ctx.stroke();
}
// 从0点向右绘制正值刻度
for (let mm = 0; originX + mm * pxPerMm <= endX; mm += 1) {
const x = originX + mm * pxPerMm;
if (x > endX) break;
if (mm % 10 === 0) continue; // 跳过主要刻度
ctx.beginPath();
ctx.moveTo(x, rulerHeight - 8);
ctx.lineTo(x, rulerHeight);
ctx.stroke();
}
}
// 绘制垂直标尺
function drawVerticalRuler() {
const ctx = document.getElementById('ruler-v').getContext('2d', { willReadFrequently: true });
ctx.clearRect(0, 0, rulerWidth, canvasHeight);
// 背景
ctx.fillStyle = '#2C2C2C';
ctx.fillRect(0, 0, rulerWidth, canvasHeight);
// 边框
ctx.strokeStyle = '#1E1E1E';
ctx.lineWidth = 1;
ctx.strokeRect(0, 0, rulerWidth, canvasHeight);
ctx.beginPath();
ctx.moveTo(rulerWidth - 1, 0);
ctx.lineTo(rulerWidth - 1, canvasHeight);
ctx.stroke();
// 刻度线
ctx.strokeStyle = '#888888';
ctx.fillStyle = '#CCCCCC';
ctx.font = '10px Arial';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
// 计算:实际画布尺寸(px)对应的物理尺寸(mm),然后根据显示区域的缩放比例计算
const pxPerMm = zoom * mmToPx; // 在显示区域中,1mm对应的像素数
const marginOffset = 20; // canvas 的 margin-top: 20px (但还要加上ruler的高度)
const rulerHeightOffset = 20; // ruler 的高度
// 标尺0点应该在background_image的左上角位置
// background_image在画布坐标系中的top值,需要转换到标尺坐标系
// 画布从标尺的marginOffset + rulerHeightOffset位置开始,所以:标尺0点 = marginOffset + rulerHeightOffset + background_image.top (如果存在)
let originY = marginOffset + rulerHeightOffset;
if (typeof background_image !== 'undefined' && background_image) {
originY = marginOffset + rulerHeightOffset + background_image.top;
}
const startY = 0;
const endY = canvasHeight;
// 绘制主要刻度(每10mm
// 从0点向上绘制负值刻度
for (let mm = -10; originY + mm * pxPerMm >= startY; mm -= 10) {
const y = originY + mm * pxPerMm;
if (y < startY) break;
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(rulerWidth, y);
ctx.stroke();
// 数字(旋转90度,负值)
ctx.save();
ctx.translate(2, y + 8);
ctx.rotate(-Math.PI / 2);
ctx.fillText(mm + 'mm', 0, 0);
ctx.restore();
}
// 从0点向下绘制正值刻度
for (let mm = 0; originY + mm * pxPerMm <= endY; mm += 10) {
const y = originY + mm * pxPerMm;
if (y > endY) break;
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(rulerWidth, y);
ctx.stroke();
// 数字(旋转90度)
ctx.save();
ctx.translate(2, y + 8);
ctx.rotate(-Math.PI / 2);
ctx.fillText(mm + 'mm', 0, 0);
ctx.restore();
}
// 绘制次要刻度(每1mm
// 从0点向上绘制负值刻度
for (let mm = -1; originY + mm * pxPerMm >= startY; mm -= 1) {
const y = originY + mm * pxPerMm;
if (y < startY) break;
if (mm % 10 === 0) continue; // 跳过主要刻度
ctx.beginPath();
ctx.moveTo(rulerWidth - 8, y);
ctx.lineTo(rulerWidth, y);
ctx.stroke();
}
// 从0点向下绘制正值刻度
for (let mm = 0; originY + mm * pxPerMm <= endY; mm += 1) {
const y = originY + mm * pxPerMm;
if (y > endY) break;
if (mm % 10 === 0) continue; // 跳过主要刻度
ctx.beginPath();
ctx.moveTo(rulerWidth - 8, y);
ctx.lineTo(rulerWidth, y);
ctx.stroke();
}
}
// 初始绘制
drawHorizontalRuler();
drawVerticalRuler();
// 监听窗口大小变化
$(window).on('resize', function () {
setTimeout(function () {
const canvasWrapper = $('.canvas-wrapper');
let newWidth = canvasWrapper.width();
let newHeight = canvasWrapper.height();
if (!newWidth || newWidth === 0) {
const canvas1Width = $('#canvas1').width() || $('#canvas-div').width() - 20;
newWidth = canvas1Width + 20; // 加上 margin-left: 20px
}
if (!newHeight || newHeight === 0) {
const canvas1Height = $('#canvas1').height() || $('#canvas-div').height() - 20;
newHeight = canvas1Height + 20; // 加上 margin-top: 20px
}
if (newWidth !== canvasWidth || newHeight !== canvasHeight) {
canvasWidth = newWidth;
canvasHeight = newHeight;
$('#ruler-h').attr('width', newWidth);
$('#ruler-v').attr('height', newHeight);
$('.ruler-horizontal').css('width', newWidth + 'px');
$('.ruler-vertical').css('height', newHeight + 'px');
drawHorizontalRuler();
drawVerticalRuler();
}
}, 100);
});
// 监听画布缩放变化
canvas1.on('after:render', function () {
drawHorizontalRuler();
drawVerticalRuler();
});
canvas2.on('after:render', function () {
drawHorizontalRuler();
drawVerticalRuler();
});
}
initRulers();
$('#source_front').width(zoom * $('#source_front').width())
$('#source_back').width(zoom * $('#source_back').width())
$('.canvas-container:eq(1)').hide()
canvas = canvas1
fabric.Object.prototype.set({
borderColor: '#9013FE',
cornerColor: '#9013FE', //激活状态角落图标的填充颜色
cornerStrokeColor: '#9013FE', //激活状态角落图标的边框颜色
borderOpacityWhenMoving: 1,
borderScaleFactor: 1,
cornerSize: 6,
cornerStyle: 'circle', //rect,circle
centeredScaling: false, //角落放大缩小是否是以图形中心为放大原点
centeredRotation: true, //旋转按钮旋转是否是左上角为圆心旋转
transparentCorners: false, //激活状态角落的图标是否透明
rotatingPointOffset: 20, //旋转距旋转体的距离
padding: 0
})
canvas1.preserveObjectStacking = true
canvas2.preserveObjectStacking = true
// ==========================================
// 对象选择和属性更新函数
// ==========================================
function updateControls() {
if (!canvas.getActiveObject()) return;
$("#text_r").val(canvas.getActiveObject().get("angle").toFixed(0));
$("#text_x").val((canvas.getActiveObject().get("left") - background_image.left).toFixed(0));
$("#text_y").val((canvas.getActiveObject().get("top") - background_image.top).toFixed(0));
$("#text_h").val((canvas.getActiveObject().get("scaleY") * canvas.getActiveObject().get("height")).toFixed(0));
$("#text_w").val((canvas.getActiveObject().get("scaleX") * canvas.getActiveObject().get("width")).toFixed(0));
if (canvas.getActiveObject().get("selectable")) {
$("#lock_img").attr("src", "public/images/unlock20.png")//已经上锁,需要解锁
} else {
$("#lock_img").attr("src", "public/images/lock20.png")//没上锁,可以上锁
}
}
function selectObject(target, index) {
updateControls();
$("#base_control").show();
}
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 + "%");
}
$("#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 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(), canvas);
$("#out_pic_field_name").val(objs[idx - 1].name);
$("#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 selectText(target, index) {
$("#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 selectCircleText(target, index) {
let idx = getIndex(canvas.getActiveObject(), canvas);
$("#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"));
if (typeof circle_text_size !== 'undefined' && circle_text_size.setValue) {
circle_text_size_updating = true; // 设置标志位
circle_text_size.setValue(canvas.getActiveObject().get("fontSize"));
circle_text_size_updating = false; // 清除标志位
} else {
$("#circle_text_size").next().children(".layui-slider-bar").css("width", ((canvas.getActiveObject().get("fontSize") - 10) / (120 - 10)) * 100 + "%");
$("#circle_text_size").next().children(".layui-slider-handle").css("left", ((canvas.getActiveObject().get("fontSize") - 10) / (120 - 10)) * 100 + "%");
}
if (typeof circle_text_diameter !== 'undefined' && circle_text_diameter.setValue) {
circle_text_diameter.setValue(canvas.getActiveObject().get("diameter"));
} else {
$("#circle_text_diameter").next().children(".layui-slider-bar").css("width", ((canvas.getActiveObject().get("diameter") - 50) / (1100 - 50)) * 100 + "%");
$("#circle_text_diameter").next().children(".layui-slider-handle").css("left", ((canvas.getActiveObject().get("diameter") - 50) / (1100 - 50)) * 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 selectOutText(target, index) {
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(), canvas);
$("#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 selectRect(target, index) {
$("#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 + "%");
}
$("#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 selectCircle(target, index) {
$("#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 selectLine(target, index) {
$("#line_control").show();
let idx = getIndex(canvas.getActiveObject(), canvas);
$("#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 selectQrCode(target, index) {
$("#qrcode_Controll").show();
let idx = getIndex(canvas.getActiveObject(), canvas);
$("#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 selectBarCode(target, index) {
$("#barcode_controll").show();
let idx = getIndex(canvas.getActiveObject(), canvas);
$("#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 selectCounter(target, index) {
$("#counter_control").show();
let idx = getIndex(canvas.getActiveObject(), canvas);
$("#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();
}
function handleObjectSelected(e) {
// 确定当前活动的 canvas(从事件参数或全局变量)
let currentCanvas = (e && e.target && (e.target.canvas === canvas1 || e.target.canvas === canvas2))
? (e.target.canvas === canvas1 ? canvas1 : canvas2)
: canvas;
// 如果事件来自 canvas,更新全局 canvas 变量
if (currentCanvas === canvas1 || currentCanvas === canvas2) {
canvas = currentCanvas;
objs = (currentCanvas === canvas1) ? objs1 : objs2;
}
let select_obj = canvas.getActiveObject();
// 1. 未选中任何对象
if (!select_obj) {
$("#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();
$("#component_type").text(language_str("bg"));
selectObj(-1, true); // 传 true,只更新UI
return;
}
// 2. 获取索引
let i = getIndex(select_obj, canvas);
if (i != 0) {
// --- 选中了普通对象 ---
--i; // 转换为 objs 数组下标
if (objs[i]) {
switch (objs[i].type) {
case 1: // 图片
$("#component_type").text(language_str("img"));
selectObject(select_obj, i); selectPic(select_obj, i); break;
case 2: // 合成图片
$("#component_type").text(language_str("simg"));
selectObject(select_obj, i); selectOutPic(select_obj, i); break;
case 3: // 文本
$("#component_type").text(language_str("text"));
selectObject(select_obj, i); selectText(select_obj, i); break;
case 4: // 合成文本
$("#component_type").text(language_str("stext"));
selectObject(select_obj, i); selectOutText(select_obj, i); break;
case 5: // 矩形
$("#component_type").text(language_str("rect"));
selectObject(select_obj, i); selectRect(select_obj, i); break;
case 6: // 圆形
$("#component_type").text(language_str("circ"));
selectObject(select_obj, i); selectCircle(select_obj, i); break;
case 7: // 直线
$("#component_type").text(language_str("line"));
selectObject(select_obj, i); selectLine(select_obj, i); break;
case 8: // 二维码
$("#component_type").text(language_str("qrc"));
selectObject(select_obj, i); selectQrCode(select_obj, i); break;
case 9: // 条形码
$("#component_type").text(language_str("barc"));
selectObject(select_obj, i); selectBarCode(select_obj, i); break;
case 10: // 计数器
$("#component_type").text(language_str("counter"));
selectObject(select_obj, i); selectCounter(select_obj, i); break;
case 11: // 圆形文本
$("#component_type").text(language_str("ctext"));
selectObject(select_obj, i); selectCircleText(select_obj, i); break;
}
}
// 【关键】这里传入 true
// 意思是:因为我已经是在画布上选中它了,selectObj 函数只负责把左边的条目变灰,不要再回头去 setActiveObject 了
selectObj(i, true);
} else {
// --- 选中了背景 ---
$("#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"));
}
}
function handleObjectMoving(e) {
let obj = e.target;
let idx = getIndex(obj, canvas);
// 圆形文本特殊处理
if (idx > 0 && idx <= objs.length && objs[idx - 1] && objs[idx - 1].type === 11 && $("#circle_text_center").prop("checked")) {
let pointer = { x: obj.left, y: obj.top };
let distance = getDisdance(pointer.x, pointer.y, canvas.width / 2, canvas.height / 2);
let angleDeg = getDeg(pointer);
let flipped = pointer.y > canvas.height / 2 ? true : false;
if (typeof circle_text_diameter !== 'undefined' && circle_text_diameter.setValue) {
circle_text_diameter.setValue(distance * 2 - 50);
}
obj.set("diameter", distance * 2);
obj.set("angle", angleDeg);
obj.set("flipped", flipped);
}
updateControls();
}
function initCanvasEvents() {
[canvas1, canvas2].forEach(currentCanvas => {
// 1. 鼠标移动
currentCanvas.on("mouse:move", (e) => {
let offsetX = 0, offsetY = 0;
if (currentCanvas === canvas2 && typeof background_image !== 'undefined') {
offsetX = background_image.left;
offsetY = background_image.top;
}
if (e.pointer) {
$("#posText").text("X: " + (e.pointer.x - offsetX).toFixed(0) + " Y: " + (e.pointer.y - offsetY).toFixed(0));
}
});
// 2. 鼠标移出
currentCanvas.on("mouse:out", () => {
// 可以在这里隐藏标尺辅助线
});
// 3. 鼠标松开 (添加对象)
currentCanvas.on("mouse:up", (e) => {
if (addState === 0) return;
const ptr = e.pointer;
switch (addState) {
case 1: addPic(ptr); break;
case 2: addOutPic(ptr); break;
case 3: addText(ptr); break;
case 4: addOutText(ptr); break;
case 5: addRect(ptr); break;
case 6: addCircle(ptr); break;
case 7: addLine(ptr); break;
case 8: addQrCode(ptr); break;
case 9: addBarCode(ptr); break;
case 10: addCounter(ptr); break;
case 11: addCircleText(ptr); break;
}
addState = 0;
if (typeof background_image !== 'undefined') background_image.hoverCursor = "default";
currentCanvas.renderAll();
$("#addPic, #addOutPic, #addText, #addOutText, #addRect, #addCircle, #addLine, #addQrCode, #addBarCode, #addCounter, #addCircleText").css("background-color", "");
});
// 4. 选中处理
currentCanvas.on('mouse:down', (e) => {
// 更新全局 canvas 变量
canvas = currentCanvas;
objs = (currentCanvas === canvas1) ? objs1 : objs2;
handleObjectSelected(e);
});
// 添加 selection 事件以确保对象选中时正确显示属性面板
currentCanvas.on('selection:created', (e) => {
canvas = currentCanvas;
objs = (currentCanvas === canvas1) ? objs1 : objs2;
handleObjectSelected(e);
});
currentCanvas.on('selection:updated', (e) => {
canvas = currentCanvas;
objs = (currentCanvas === canvas1) ? objs1 : objs2;
handleObjectSelected(e);
});
currentCanvas.on('object:selected', (e) => {
canvas = currentCanvas;
objs = (currentCanvas === canvas1) ? objs1 : objs2;
handleObjectSelected(e);
});
// 5. 对象移动
currentCanvas.on("object:moving", (e) => {
handleObjectMoving(e);
});
// 6. 变换事件
currentCanvas.on("object:rotating", updateControls);
currentCanvas.on("object:scaling", updateControls);
currentCanvas.on("object:rotated", () => { recordState(); });
currentCanvas.on('text:editing:entered', () => { _textEdit = true; });
currentCanvas.on('text:editing:exited', () => { _textEdit = false; });
currentCanvas.on("text:changed", (e) => { $("#text_text").val(e.target.get("text")); });
// 7. 对象修改后
currentCanvas.on('object:modified', function (event) {
if (currentCanvas.getActiveObjects().length > 1) return;
let idx = getIndex(event.target, currentCanvas);
if (idx <= 0) return;
let objData = objs[idx - 1];
let target = event.target;
if ([3, 4, 10].includes(objData.type)) {
target.fontSize = (target.fontSize * target.scaleX).toFixed(0);
target.scaleX = 1; target.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();
}
recordState();
});
});
}
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));
// 组装 HTML
str = `<div style="${rowStyle}">
<div style="${leftStyle}">
<img src="public/images/${iconName}" id="obj${i}" style="width:16px; margin-right:5px;">
<span title="${nameText}">${nameText}</span>
</div>
<span style="${indexStyle}">${displayIndex}</span>
</div>` + str;
i++;
}
$(".obj_list").html(str);
// 重新绑定点击事件(防止 updateList 后点击失效)
$(".obj_list > div").on("click", function () {
let imgId = $(this).find("img").attr("id");
if (imgId) {
let idx = parseInt(imgId.replace("obj", ""));
selectObj(idx);
}
});
}
function selectObj(objIndices, isFromCanvas = false) {
let indicesArray = (Array.isArray(objIndices)) ? objIndices : ((typeof objIndices === 'number' && objIndices >= 0) ? [objIndices] : []);
// 清除所有高亮
$('.obj_list > div').css("background-color", "transparent");
// 遍历列表查找并高亮
$('.obj_list > div').each(function () {
let $img = $(this).find("img");
if ($img.length === 0) return;
let idIndex = parseInt($img.attr("id").replace("obj", ""));
if (indicesArray.includes(idIndex)) {
$(this).css("background-color", "#6F7A84");
// 自动滚动到可视区域
if (isFromCanvas && indicesArray[0] === idIndex) {
this.scrollIntoView({ behavior: "smooth", block: "nearest" });
}
}
});
// 如果是点击列表,触发画布选中
if (!isFromCanvas && indicesArray.length === 1) {
let target = canvas.getObjects()[indicesArray[0] + 1];
if (target) {
canvas.setActiveObject(target);
canvas.requestRenderAll();
handleObjectSelected();
}
}
}
function recordState() {
++step.val;
for (let i = step.val; i < recordObjs.length; i++) {
recordObjs.pop();
recordJson.pop();
}
recordObjs.push(JSON.stringify(objs))
j = canvas.toJSON(["selectable", "hoverable", "hoverCursor", "text", "fontStyle", "fontWeight", "underline"]);
j.objects[0].hoverCursor = "default";
recordJson.push(j);
}
function getIndex(target, _canvas = null) {
let temp_objs;
if (_canvas == null) {
temp_objs = canvas.getObjects();
} else {
temp_objs = _canvas.getObjects();
}
let i = 0;
for (let res of temp_objs) {
if (target == res) {
return i;
}
i++;
}
return 0;
}
function getType(target) {
let temp_objs = canvas.getObjects();
let i = 0;
for (let res of temp_objs) {
if (target == res) {
return objs[i].type;
}
i++;
}
}
function checkName(name) {
//检查字段名是否重复了
for (let item of objs1) {
if (item.name == name) {
return false;
}
}
for (let item of objs2) {
if (item.name == name) {
return false;
}
}
return true;
}
function resName(pre_name) {
//返回的是不重复的字段名
let num = (objs1.length + objs2.length) - 1;
do {
num++;
}
while (!checkName(pre_name + num));//重复了就再加1
return pre_name + num;
}
function getDisdance(x1, y1, x2, y2) {
var dx = Math.abs(x2 - x1); // 计算x轴上的距离差,并取绝对值
var dy = Math.abs(y2 - y1); // 计算y轴上的距离差,并取绝对值
var distance = Math.sqrt(dx * dx + dy * dy); // 应用勾股定理计算距离
return distance;
}
function getDeg(pointer) {
// 计算点击位置与画布中心的坐标差
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var mouseX = pointer.x;
var mouseY = pointer.y;
var dx = mouseX - centerX;
var dy = mouseY - centerY;
// 计算旋转角度(弧度)
var angleRad = Math.atan2(dy, dx);
// 将角度转换为度数
var angleDeg = angleRad * (180 / Math.PI);
if (angleDeg < 0) {
angleDeg += 360;
}
angleDeg += 90
return angleDeg
}
function getCoordsMinX(acoords) {
x = acoords[0].x;
for (let item of acoords) {
if (item.x < x) {
x = item.x
}
}
return x;
}
function getCoordsMaxX(acoords) {
x = acoords[0].x;
for (let item of acoords) {
if (item.x > x) {
x = item.x
}
}
return x;
}
function getCoordsMinY(acoords) {
y = acoords[0].y;
for (let item of acoords) {
if (item.y < y) {
y = item.y
}
}
return y;
}
function getCoordsMaxY(acoords) {
y = acoords[0].y;
for (let item of acoords) {
if (item.y > y) {
y = item.y
}
}
return y;
}
function addBackground() {
// 类型改变
fabric.Image.fromURL('./public/images/bg_front_2.png', function (image) {
image.left = ($('#canvas1').width() - image.width * image.get('scaleX')) / 2
image.top = ($('#canvas1').height() - image.height * image.get('scaleY')) / 2
image.selectable = false
image.hoverable = false
image.hoverCursor = 'default'
image.setSrc(image.toDataURL(), function (image) {
background_image1 = image
background_image = background_image1
canvas1.add(image)
canvas1.renderAll()
recordObjs1.push(JSON.stringify(objs1))
recordJson1.push(canvas1.toJSON(['selectable', 'hoverable', 'hoverCursor', 'text', 'fontStyle', 'fontWeight', 'underline']))
})
// 类型改变
fabric.Image.fromURL('./public/images/bg_back_2.png', function (image) {
image.left = ($('#canvas2').width() - image.width) / 2
image.top = ($('#canvas2').height() - image.height) / 2
image.selectable = false
image.hoverable = false
image.hoverCursor = 'default'
image.setSrc(image.toDataURL(), function (image) {
background_image2 = image
canvas2.add(image)
canvas2.renderAll()
recordObjs2.push(JSON.stringify(objs2))
recordJson2.push(canvas2.toJSON(['selectable', 'hoverable', 'hoverCursor', 'text', 'fontStyle', 'fontWeight', 'underline']))
let file = GetFile().get('file')
if (file && file != 'empty') {
open(file)
}
})
})
is_bgi_add = true
})
}
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()
recordState()
}
function addOutPic(pointer) {
fabric.Image.fromURL('./public/images/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.setSrc(image.toDataURL(), function (image) {
canvas.add(image)
objs.push({ type: 2, name: resName('OUT_PIC_'), black: false })
canvas.renderAll()
updateList()
recordState()
})
})
}
function addText(pointer) {
let text = new fabric.IText('TEXT', {
left: pointer.x,
top: pointer.y,
fill: '#000000',
textBackgroundColor: '',
fontStyle: 'normal',
fontWeight: 'normal',
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()
recordState()
}
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: 30,
underline: false,
linethrough: false,
lockScalingX: true,
lockScalingY: true,
fontFamily: 'Arial',
originX: 'center',
originY: 'center',
angle: angleDeg,
flipped: pointer.y > canvas.height / 2 ? true : false
});
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, circleCenter: 0 });
canvas.renderAll();
updateList();
recordState();
}
function addOutText(pointer) {
let text = new fabric.Text('MERGE TEXT', {
left: pointer.x,
top: pointer.y,
fill: '#000000',
fontStyle: 'normal',
fontWeight: 'normal',
textBackgroundColor: '',
underline: false,
linethrough: false,
fontFamily: 'Arial',
textAlign: 'center'
})
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()
recordState()
}
function addRect(pointer) {
let rect = new fabric.Rect({
left: pointer.x,
top: pointer.y,
fill: '',
stroke: "#ff0000",
strokeWidth: 3,
width: 100,
height: 100
})
canvas.add(rect)
objs.push({ type: 5, black: false })
canvas.renderAll()
updateList()
recordState()
}
function addCircle(pointer) {
let circle = new fabric.Circle({
left: pointer.x,
top: pointer.y,
fill: '',
stroke: '#ff0000',
strokeWidth: 3,
radius: 100,
strokeUniform: true
})
canvas.add(circle)
objs.push({ type: 6, black: false })
canvas.renderAll()
updateList()
recordState()
}
function addLine(pointer) {
let line = new fabric.Line([50, 100, 200, 100], {
left: pointer.x,
top: pointer.y,
stroke: '#ff0000',
strokeWidth: 3,
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()
recordState()
}
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
canvas.add(image)
objs.push({ type: 8, name: resName('QR_CODE_'), color: '#000000', val: 'http://www.cardsoon.com', black: false })
canvas.renderAll()
updateList()
recordState()
})
}
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
canvas.add(image)
objs.push({ type: 9, name: resName('BAR_CODE_'), val: '123456789', color: '#000000', fontSize: 18, font: 'Arial', show: false, black: false })
canvas.renderAll()
updateList()
recordState()
})
}
function addCounter(pointer) {
let text = new fabric.Text('0', {
left: pointer.x,
top: pointer.y,
fill: '#000000'
})
canvas.add(text)
objs.push({ type: 10, name: resName('COUNTER_'), start: 0, add: 1, black: false })
canvas.renderAll()
updateList()
recordState()
}
var front_list = []
ipcRenderer.on('font-list', (event, data) => {
const newFontList = []
data.map((item) => {
if (item.indexOf('"') === 0) {
newFontList.push(item.replace(/^"|"$/g, ''))
} else {
newFontList.push(item)
}
})
front_list = newFontList
for (let item of front_list) {
$('#text_font_family').append("<option value='" + item + "'>" + item + '</option>')
$("#circle_text_font_family").append("<option value='" + item + "'>" + item + "</option>");
$('#out_text_font_family').append("<option value='" + item + "'>" + item + '</option>')
$('#barcode_font_family').append("<option value='" + item + "'>" + item + '</option>')
$('#count_font_family').append("<option value='" + item + "'>" + item + '</option>')
}
})
ipcRenderer.on('sys-lan', (event, data) => {
let lang = localStorage.getItem('lang')
if (lang) {
s_lan = lang
langua_ge(lang)
$('#language_select').val(lang)
return
}
switch (data) {
case 'zh-CN':
s_lan = 'zh'
langua_ge('zh')
$('#language_select').val('zh')
localStorage.setItem('lang', 'zh')
break
case 'zh':
s_lan = 'zh'
langua_ge('zh')
$('#language_select').val('zh')
localStorage.setItem('lang', 'zh')
break
case 'zh-TW':
s_lan = 'ozh'
langua_ge('ozh')
$('#language_select').val('ozh')
localStorage.setItem('lang', 'ozh')
break
case 'en':
s_lan = 'en'
langua_ge('en')
$('#language_select').val('en')
localStorage.setItem('lang', 'en')
break
case 'en-AU':
s_lan = 'en'
langua_ge('en')
$('#language_select').val('en')
localStorage.setItem('lang', 'en')
break
case 'en-CA':
s_lan = 'en'
langua_ge('en')
$('#language_select').val('en')
localStorage.setItem('lang', 'en')
break
case 'en-GB':
s_lan = 'en'
langua_ge('en')
$('#language_select').val('en')
localStorage.setItem('lang', 'en')
break
case 'en-NZ':
s_lan = 'en'
langua_ge('en')
$('#language_select').val('en')
localStorage.setItem('lang', 'en')
break
case 'en-US':
s_lan = 'en'
langua_ge('en')
$('#language_select').val('en')
localStorage.setItem('lang', 'en')
break
case 'en-ZA':
s_lan = 'en'
langua_ge('en')
$('#language_select').val('en')
localStorage.setItem('lang', 'en')
break
}
})
ipcRenderer.on('close', (event, message) => {
layer.confirm(
'<font style="color:black">' + language_str('whetherSave') + '</font>',
{
//是否保存当前文件?
btn: [language_str('save'), language_str('noSave'), language_str('cancel')], //['保存', '不保存', '取消']
btn3: function (index, layero) { }
},
function (index, layero) {
output(() => ipcRenderer.send('run-close'))
},
function (index) {
ipcRenderer.send('run-close')
}
)
})
addBackground() //添加背景 白色卡片
initAligningGuidelines(canvas1)
initAligningGuidelines(canvas2)
// 初始化 Canvas 事件监听
initCanvasEvents();
// 初始化所有 Slider
var circle_text_size_updating = false; // 标志位,防止循环更新
var circle_text_size = slider.render({
elem: '#circle_text_size',
min: 10,
max: 120,
value: 50,
change: function (value) {
if (circle_text_size_updating) return; // 如果正在更新slider,跳过change事件
if (canvas.getActiveObject()) {
canvas.getActiveObject().set('fontSize', value);
canvas.renderAll();
updateControls();
recordState();
}
}
});
var circle_text_diameter = slider.render({
elem: '#circle_text_diameter',
min: 50,
max: 1100,
value: 500,
change: function (value) {
if (canvas.getActiveObject()) {
canvas.getActiveObject().set('diameter', value);
canvas.renderAll();
updateControls();
recordState();
}
}
});
var out_pic_op = slider.render({
elem: '#out_pic_op',
min: 0,
max: 100,
value: 0,
change: function (value) {
if (canvas.getActiveObject()) {
canvas.getActiveObject().set('opacity', 1 - value / 100);
canvas.renderAll();
updateControls();
recordState();
}
}
});
var pic_op = slider.render({
elem: '#pic_op',
min: 0,
max: 100,
value: 0,
change: function (value) {
if (canvas.getActiveObject()) {
canvas.getActiveObject().set('opacity', 1 - value / 100);
canvas.renderAll();
updateControls();
recordState();
}
}
});
var rect_op = slider.render({
elem: '#rect_op',
min: 0,
max: 100,
value: 0,
change: function (value) {
if (canvas.getActiveObject()) {
canvas.getActiveObject().set('opacity', 1 - value / 100);
canvas.renderAll();
updateControls();
recordState();
}
}
});
var circle_op = slider.render({
elem: '#circle_op',
min: 0,
max: 100,
value: 0,
change: function (value) {
if (canvas.getActiveObject()) {
canvas.getActiveObject().set('opacity', 1 - value / 100);
canvas.renderAll();
updateControls();
recordState();
}
}
});
//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() //重新渲染画布
var zoomSlider = slider.render({
elem: '#zoomSlide', //绑定元素
min: 25,
max: 500,
value: 100,
change(val) {
canvas.zoomToPoint(new fabric.Point(canvas.width / 2, canvas.height / 2), val / 100)
zoom = val / 100
//$(".canvas-container").css("transform","scale(" + val / 100 + ")")
}
})
window.rotate = function (id) {
let angle = $(`#${id}`).attr('angle') - 0
angle += 90
$(`#${id}`).css('transform', `rotate(${angle}deg)`)
$(`#${id}`).attr('angle', angle)
}
$('#display').on('click', function () {
// 类型改变
fabric.Image.fromURL('./public/images/front_bg' + bg_version + '_2.png', function (i1) {
i1.left = background_image.left
i1.top = background_image.top
let img1 = i1
fabric.Image.fromURL('./public/images/back_bg_2.png', function (i2) {
i2.left = background_image.left
i2.top = background_image.top
let img2 = i2
fabric.Image.fromURL('./public/images/op_2.png', function (i3) {
i2.left = background_image.left
i2.top = background_image.top
let img3 = i3
display_func(img1, img2, img3)
})
})
})
})
// 导出文件
async function savePdf(buffer) {
let fs = require('fs');
// 弹出保存对话框
const { canceled, filePath } = await dialog.showSaveDialog({
title: '保存文件',
defaultPath: path.join(exePath, 'output.pdf'), // 默认路径
filters: [{ name: 'PDF 文件', extensions: ['pdf'] }] // 文件过滤器
});
if (canceled) {
console.log('用户取消了保存操作');
return;
}
// 将Buffer写入PNG文件到用户选择的路径
fs.writeFile(filePath, buffer, (err) => {
if (err) {
console.error('写入文件失败:', err);
} else {
layer.msg(language_str("saveSucc") + filePath);//'保存成功至'
console.log('PNG文件已保存至:', filePath);
}
});
}
function display_func(img1, img2, img3) {
$('#base_control').hide()
$('#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()
$('#barcode_controll').hide()
$('#component_type').text(language_str('bg')) //"背景"
canvas1.discardActiveObject().renderAll()
canvas2.discardActiveObject().renderAll()
let _objs1 = canvas1.getObjects()
let g1 = []
let g3 = []
let g5 = []
let left = 0 //左裁剪
let top = 0 //顶裁剪
let black_left = 0 //黑色左裁剪
let black_top = 0 //黑色顶裁剪
let all_left = 0 //预览图左裁剪
let all_top = 0 //预览图顶裁剪
for (let item of _objs1) {
let idx = getIndex(item, canvas1)
//console.log("------");
//console.log(item.getCoords());
//console.log(getCoordsMinX(background_image.getCoords()));
//console.log(getCoordsMinX(item.getCoords()));
//console.log(getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()));
//console.log("------");
if (getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()) > all_left) {
all_left = -(getCoordsMinX(item.getCoords()) - getCoordsMinX(background_image.getCoords()))
}
if (getCoordsMinY(background_image.getCoords()) - getCoordsMinY(item.getCoords()) > all_top) {
all_top = -(getCoordsMinY(item.getCoords()) - getCoordsMinY(background_image.getCoords()))
}
g3.push(fabric.util.object.clone(item))
if (idx != 0 && (objs1[idx - 1].type == 10 || objs1[idx - 1].type == 4)) {
continue //计数器 或 合成文字
}
if (idx != 0 && (objs1[idx - 1].type == 8 || objs1[idx - 1].type == 9)) {
continue //二维码 条形码
}
if (idx != 0 && objs1[idx - 1].type == 2) {
continue //合成图片
}
if (
idx != 0 &&
((objs1[idx - 1].type == 3 && (item.get('fill') == '#000000' || (item.get('fill') == '#ffffff' && false))) ||
(
objs1[idx - 1].type == 11
&&
(item.get("fill") == "#000000" || (item.get("fill") == "#ffffff" && false))
//圆形文字 && 黑色
) ||
//文字 && 黑色
(objs1[idx - 1].type == 5 && //矩形
(((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('stroke') == '') || //黑填充 透明边框
(item.get('fill') == '' && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //透明填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //黑填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('strokeWidth') == 0))) || //黑填充 0边框
(objs1[idx - 1].type == 6 && //圆形
(((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('stroke') == '') || //黑填充 透明边框
(item.get('fill') == '' && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //透明填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //黑填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('strokeWidth') == 0))) || //黑填充 0边框
(objs1[idx - 1].type == 7 && //直线
(item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) ||
objs1[idx - 1].black == true) //勾选并入黑色图层
// (
// objs1[idx-1].type == 1//固定图片
// &&
// objs1[idx-1].black == true //勾选并入黑色图层
// )
) {
if (getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()) > black_left) {
black_left = -(getCoordsMinX(item.getCoords()) - getCoordsMinX(background_image.getCoords()))
}
if (getCoordsMinY(background_image.getCoords()) - getCoordsMinY(item.getCoords()) > black_top) {
black_top = -(getCoordsMinY(item.getCoords()) - getCoordsMinY(background_image.getCoords()))
}
g5.push(fabric.util.object.clone(item))
continue //黑色文字 黑色矩形 黑色线条 黑色圆形
} else if (idx == 0) {
g5.push(fabric.util.object.clone(item))
}
if (getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()) > left) {
left = -(getCoordsMinX(item.getCoords()) - getCoordsMinX(background_image.getCoords()))
}
if (getCoordsMinY(background_image.getCoords()) - getCoordsMinY(item.getCoords()) > top) {
top = -(getCoordsMinY(item.getCoords()) - getCoordsMinY(background_image.getCoords()))
}
g1.push(fabric.util.object.clone(item))
}
let url1 = new fabric.Group(g1).toDataURL({
height: 648,
width: 1012,
top: top / zoom,
left: left / zoom
})
// g3.push(img1)
let url3 = new fabric.Group(g3).toDataURL({
height: 648,
width: 1012,
top: all_top / zoom,
left: all_left / zoom
})
let url5 = new fabric.Group(g5).toDataURL({
height: 648,
width: 1012,
top: black_top / zoom,
left: black_left / zoom
})
let _objs2 = canvas2.getObjects()
let g2 = []
let g4 = []
let g6 = []
left = 0
top = 0
black_top = 0
black_left = 0
all_top = 0
all_left = 0
for (let item of _objs2) {
let idx = getIndex(item, canvas2)
if (getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()) > all_left) {
all_left = -(getCoordsMinX(item.getCoords()) - getCoordsMinX(background_image.getCoords()))
}
if (getCoordsMinY(background_image.getCoords()) - getCoordsMinY(item.getCoords()) > all_top) {
all_top = -(getCoordsMinY(item.getCoords()) - getCoordsMinY(background_image.getCoords()))
}
g4.push(fabric.util.object.clone(item))
if (idx != 0 && (objs2[idx - 1].type == 10 || objs2[idx - 1].type == 4)) {
continue //黑色字或计数器 或 合成文字
}
if (idx != 0 && (objs2[idx - 1].type == 8 || objs2[idx - 1].type == 9)) {
continue //二维码 条形码
}
if (idx != 0 && objs2[idx - 1].type == 2) {
continue //合成图片
}
if (idx != 0 && objs2[idx - 1].type == 10) {
continue //合成图片
}
if (
idx != 0 &&
((objs2[idx - 1].type == 3 && (item.get('fill') == '#000000' || (item.get('fill') == '#ffffff' && false))) ||
(
objs2[idx - 1].type == 11
&&
(item.get("fill") == "#000000" || (item.get("fill") == "#ffffff" && false))
//圆形文字 && 黑色
) ||
//文字 && 黑色
(objs2[idx - 1].type == 5 && //矩形
(((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('stroke') == '') || //黑填充 透明边框
(item.get('fill') == '' && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //透明填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //黑填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('strokeWidth') == 0))) || //黑填充 0边框
(objs2[idx - 1].type == 6 && //圆形
(((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('stroke') == '') || //黑填充 透明边框
(item.get('fill') == '' && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //透明填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //黑填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('strokeWidth') == 0))) || //黑填充 0边框
(objs2[idx - 1].type == 7 && //直线
(item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) ||
objs2[idx - 1].black == true) //勾选并入黑色图层
// (
// objs2[idx-1].type == 1//固定图片
// &&
// objs2[idx-1].black == true //勾选并入黑色图层
// )
) {
if (getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()) > black_left) {
black_left = -(getCoordsMinX(item.getCoords()) - getCoordsMinX(background_image.getCoords()))
}
if (getCoordsMinY(background_image.getCoords()) - getCoordsMinY(item.getCoords()) > black_top) {
black_top = -(getCoordsMinY(item.getCoords()) - getCoordsMinY(background_image.getCoords()))
}
g6.push(fabric.util.object.clone(item))
continue //黑色文字 黑色矩形 黑色线条 黑色圆形
} else if (idx == 0) {
g6.push(fabric.util.object.clone(item))
}
if (getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()) > left) {
left = -(getCoordsMinX(item.getCoords()) - getCoordsMinX(background_image.getCoords()))
}
if (getCoordsMinY(background_image.getCoords()) - getCoordsMinY(item.getCoords()) > top) {
top = -(getCoordsMinY(item.getCoords()) - getCoordsMinY(background_image.getCoords()))
}
g2.push(fabric.util.object.clone(item))
}
let url2 = new fabric.Group(g2).toDataURL({
height: 648,
width: 1012,
top: top / zoom,
left: left / zoom
})
let white_url1 = canvas1.getObjects()[0].toDataURL({
height: 648,
width: 1012
})
// g4.push(img2)
let url4 = new fabric.Group(g4).toDataURL({
height: 648,
width: 1012,
top: all_top / zoom,
left: all_left / zoom
})
let url6 = new fabric.Group(g6).toDataURL({
height: 648,
width: 1012,
top: black_top / zoom,
left: black_left / zoom
})
let white_url2 = canvas2.getObjects()[0].toDataURL({
height: 648,
width: 1012
})
//console.log(canvas.getObjects())
let w = document.body.clientWidth * 0.7 + 'px'
let h = (document.body.clientWidth * 0.7 - 40 - 0.06 * document.body.clientWidth * 0.7) * 0.62548 + 150 + 'px'
let h1 = (document.body.clientWidth * 0.7 - 40 - 0.06 * document.body.clientWidth * 0.7) * 0.62548 + 'px'
if ((document.body.clientWidth * 0.7 - 40 - 0.06 * document.body.clientWidth * 0.7) * 0.62548 > document.body.clientHeight) {
//高度超出,则按高度计算
h = document.body.clientHeight * 0.8 + 'px'
h1 = document.body.clientHeight * 0.8 - 150 + 'px'
w = ((document.body.clientHeight * 0.8 - 150) / 0.62548 + 40) / 0.94
}
let fs = require('fs');
const Buffer = require('buffer').Buffer;
const buffer3 = Buffer.from(url3.replace(/^data:image\/\w+;base64,/, ""), 'base64');
const printPath3 = path.join(exePath, 'print3.png');
fs.writeFileSync(printPath3, buffer3);
const buffer4 = Buffer.from(url4.replace(/^data:image\/\w+;base64,/, ""), 'base64');
const printPath4 = path.join(exePath, 'print4.png');
fs.writeFileSync(printPath4, buffer4);
// 创建 PDF 实例
const pdf = new jspdf.jsPDF({
orientation: 'landscape',
unit: 'px',
format: [1012, 648]
});
let btns = [language_str('output')]
if ((objs1.length != 0) & (objs2.length == 0)) {
//只有正面
let img = new Image()
img.src = printPath3
pdf.addImage(img, 'JPEG', 0, 0, 1012, 648)
btns.push('打印正面')
} else if ((objs1.length == 0) & (objs2.length != 0)) {
//只有背面
let img = new Image()
img.src = printPath4
pdf.addImage(img, 'JPEG', 0, 0, 1012, 648)
btns.push('打印背面')
} else {
let img = new Image()
img.src = printPath3
pdf.addImage(img, 'JPEG', 0, 0, 1012, 648)
pdf.addPage()
let img2 = new Image()
img2.src = printPath4
pdf.addImage(img2, 'JPEG', 0, 0, 1012, 648)
btns.push('打印正面')
btns.push('打印背面')
}
var pdfBlob = pdf.output('blob')
var pdfBuffer = pdf.output('arraybuffer')
layer.open({
type: 1,
area: [w, h],
title: language_str('display'), //不显示标题栏"预览"
shadeClose: true, //点击遮罩关闭
content: `
<div style="padding:20px;background-color:#1E252D;height:${h1};display:flex;align-items: center;overflow:hidden;">
<div style="/*position: relative;top: 50%;transform: translateY(-50%);*/display: flex;justify-content: space-between;">
<div class="rotate-div" id="displayImg1" angle="0">
<img src="${printPath3}" style="width:95%"/>
<div class="rotate-wrap" onclick="window.rotate('displayImg1')">
<img src="./public/images/rotate.png" style="height: 64px;width: 64px"/>
</div>
</div>
<div class="rotate-div" id="displayImg2" angle="0">
<img style="width:95%;/*margin-left:6%*/" src="${printPath4}"/>
<div class="rotate-wrap" onclick="window.rotate('displayImg2')">
<img src="./public/images/rotate.png" style="height: 64px;width: 64px"/>
</div>
</div>
</div>
</div>`,
btn: btns, //'导出'
btn1: function (index, layero) {
savePdf(Buffer.from(pdfBuffer))
},
btn2: function () {
if (btns[1] === '打印正面') {
printJS({ printable: printPath3, type: 'image', style: 'img { width: 100%; height: auto; }' })
} else {
printJS({ printable: printPath4, type: 'image', style: 'img { width: 100%; height: auto; }' })
}
},
btn3: function () {
//打印背面
printJS({ printable: printPath4, type: 'image', style: 'img { width: 100%; height: auto; }' })
}
})
}
function output(callback = null, _save = save) {
// 类型改变
fabric.Image.fromURL('./public/images/op_2.png', function (i1) {
i1.left = background_image.left
i1.top = background_image.top
let img1 = i1
fabric.Image.fromURL('./public/images/op_2.png', function (i2) {
i2.left = background_image.left
i2.top = background_image.top
let img2 = i2
$('#base_control').hide()
$('#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()
$('#barcode_controll').hide()
$('#component_type').text(language_str('bg')) //"背景"
canvas1.discardActiveObject().renderAll()
canvas2.discardActiveObject().renderAll()
let _objs1 = canvas1.getObjects()
let g1 = []
let g3 = []
let g5 = [] //黑色图层
let left = 0 //左裁剪
let top = 0 //顶裁剪
let black_left = 0 //黑色左裁剪
let black_top = 0 //黑色顶裁剪
let all_left = 0 //预览图左裁剪
let all_top = 0 //预览图顶裁剪
for (let item of _objs1) {
let idx = getIndex(item, canvas1)
//console.log("------");
//console.log(item.getCoords());
//console.log(getCoordsMinX(background_image.getCoords()));
//console.log(getCoordsMinX(item.getCoords()));
//console.log(getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()));
//console.log("------");
if (getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()) > all_left) {
all_left = -(getCoordsMinX(item.getCoords()) - getCoordsMinX(background_image.getCoords()))
}
if (getCoordsMinY(background_image.getCoords()) - getCoordsMinY(item.getCoords()) > all_top) {
all_top = -(getCoordsMinY(item.getCoords()) - getCoordsMinY(background_image.getCoords()))
}
g3.push(fabric.util.object.clone(item))
if (idx != 0 && (objs1[idx - 1].type == 10 || objs1[idx - 1].type == 4)) {
continue //计数器 或 合成文字
}
if (idx != 0 && (objs1[idx - 1].type == 8 || objs1[idx - 1].type == 9)) {
continue //二维码 条形码
}
if (idx != 0 && objs1[idx - 1].type == 2) {
continue //合成图片
}
if (
idx != 0 &&
((objs1[idx - 1].type == 3 && item.get('fill') == '#000000') ||
(
objs1[idx - 1].type == 11
&&
item.get("fill") == "#000000"
//圆形文字 && 黑色
) ||
//文字 && 黑色
(objs1[idx - 1].type == 5 && //矩形
(((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('stroke') == '') || //黑填充 透明边框
(item.get('fill') == '' && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //透明填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //黑填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('strokeWidth') == 0))) || //黑填充 0边框
(objs1[idx - 1].type == 6 && //圆形
(((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('stroke') == '') || //黑填充 透明边框
(item.get('fill') == '' && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //透明填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //黑填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('strokeWidth') == 0))) || //黑填充 0边框
(objs1[idx - 1].type == 7 && //直线
(item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) ||
objs1[idx - 1].black == true) //勾选并入黑色图层
// ||
// (
// objs1[idx-1].type == 1//固定图片
// &&
// objs1[idx-1].black == true //勾选并入黑色图层
// )
) {
if (getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()) > black_left) {
black_left = -(getCoordsMinX(item.getCoords()) - getCoordsMinX(background_image.getCoords()))
}
if (getCoordsMinY(background_image.getCoords()) - getCoordsMinY(item.getCoords()) > black_top) {
black_top = -(getCoordsMinY(item.getCoords()) - getCoordsMinY(background_image.getCoords()))
}
g5.push(fabric.util.object.clone(item))
continue //黑色文字 黑色矩形 黑色线条 黑色圆形
} else if (idx == 0) {
g5.push(fabric.util.object.clone(item))
}
if (getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()) > left) {
left = -(getCoordsMinX(item.getCoords()) - getCoordsMinX(background_image.getCoords()))
}
if (getCoordsMinY(background_image.getCoords()) - getCoordsMinY(item.getCoords()) > top) {
top = -(getCoordsMinY(item.getCoords()) - getCoordsMinY(background_image.getCoords()))
}
g1.push(fabric.util.object.clone(item))
}
let url1 = new fabric.Group(g1).toDataURL({
height: 648,
width: 1012,
top: top / zoom,
left: left / zoom
})
g3.push(img1)
let url3 = new fabric.Group(g3).toDataURL({
height: 648,
width: 1012,
top: all_top / zoom,
left: all_left / zoom
})
let url5 = new fabric.Group(g5).toDataURL({
height: 648,
width: 1012,
top: black_top / zoom,
left: black_left / zoom
})
let _objs2 = canvas2.getObjects()
let g2 = []
let g4 = []
let g6 = [] //黑色图层
left = 0
top = 0
black_left = 0 //黑色左裁剪
black_top = 0 //黑色顶裁剪
all_left = 0 //黑色左裁剪
all_top = 0 //黑色顶裁剪
for (let item of _objs2) {
let idx = getIndex(item, canvas2)
if (getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()) > all_left) {
all_left = -(getCoordsMinX(item.getCoords()) - getCoordsMinX(background_image.getCoords()))
}
if (getCoordsMinY(background_image.getCoords()) - getCoordsMinY(item.getCoords()) > all_top) {
all_top = -(getCoordsMinY(item.getCoords()) - getCoordsMinY(background_image.getCoords()))
}
g4.push(fabric.util.object.clone(item))
if (idx != 0 && (objs2[idx - 1].type == 10 || objs2[idx - 1].type == 4)) {
continue //计数器 或 合成文字
}
if (idx != 0 && (objs2[idx - 1].type == 8 || objs2[idx - 1].type == 9)) {
continue //二维码 条形码
}
if (idx != 0 && objs2[idx - 1].type == 2) {
continue //合成图片
}
if (
idx != 0 &&
((objs2[idx - 1].type == 3 && (item.get('fill') == '#000000' || (item.get('fill') == '#ffffff' && false))) ||
(
objs2[idx - 1].type == 11
&&
(item.get("fill") == "#000000" || (item.get("fill") == "#ffffff" && false))
//圆形文字 && 黑色
) ||
//文字 && 黑色
(objs2[idx - 1].type == 5 && //矩形
(((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('stroke') == '') || //黑填充 透明边框
(item.get('fill') == '' && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //透明填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //黑填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('strokeWidth') == 0))) || //黑填充 0边框
(objs2[idx - 1].type == 6 && //圆形
(((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('stroke') == '') || //黑填充 透明边框
(item.get('fill') == '' && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //透明填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && (item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) || //黑填充 黑边框
((item.get('fill') == '#000000' || item.get('fill') == '#ffffff') && item.get('strokeWidth') == 0))) || //黑填充 0边框
(objs2[idx - 1].type == 7 && //直线
(item.get('stroke') == '#000000' || item.get('stroke') == '#ffffff')) ||
objs2[idx - 1].black == true) //勾选并入黑色图层
// (
// objs2[idx-1].type == 1//固定图片
// &&
// objs2[idx-1].black == true //勾选并入黑色图层
// )
) {
if (getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()) > black_left) {
black_left = -(getCoordsMinX(item.getCoords()) - getCoordsMinX(background_image.getCoords()))
}
if (getCoordsMinY(background_image.getCoords()) - getCoordsMinY(item.getCoords()) > black_top) {
black_top = -(getCoordsMinY(item.getCoords()) - getCoordsMinY(background_image.getCoords()))
}
g6.push(fabric.util.object.clone(item))
continue //黑色文字 黑色矩形 黑色线条 黑色圆形
} else if (idx == 0) {
g6.push(fabric.util.object.clone(item))
}
if (getCoordsMinX(background_image.getCoords()) - getCoordsMinX(item.getCoords()) > left) {
left = -(getCoordsMinX(item.getCoords()) - getCoordsMinX(background_image.getCoords()))
}
if (getCoordsMinY(background_image.getCoords()) - getCoordsMinY(item.getCoords()) > top) {
top = -(getCoordsMinY(item.getCoords()) - getCoordsMinY(background_image.getCoords()))
}
g2.push(fabric.util.object.clone(item))
}
let url2 = new fabric.Group(g2).toDataURL({
height: 648,
width: 1012,
top: top / zoom,
left: left / zoom
})
let white_url1 = canvas1.getObjects()[0].toDataURL({
height: 648,
width: 1012
})
g4.push(img2)
let url4 = new fabric.Group(g4).toDataURL({
height: 648,
width: 1012,
top: all_top / zoom,
left: all_left / zoom
})
let url6 = new fabric.Group(g6).toDataURL({
height: 648,
width: 1012,
top: black_top / zoom,
left: black_left / zoom
})
let white_url2 = canvas2.getObjects()[0].toDataURL({
height: 648,
width: 1012
})
//console.log(canvas.getObjects())
let w = document.body.clientWidth * 0.7 + 'px'
let h = (document.body.clientWidth * 0.7 - 40 - 0.06 * document.body.clientWidth * 0.7) * 0.62548 + 150 + 'px'
let h1 = (document.body.clientWidth * 0.7 - 40 - 0.06 * document.body.clientWidth * 0.7) * 0.62548 + 'px'
if ((document.body.clientWidth * 0.7 - 40 - 0.06 * document.body.clientWidth * 0.7) * 0.62548 > document.body.clientHeight) {
//高度超出,则按高度计算
h = document.body.clientHeight * 0.8 + 'px'
h1 = document.body.clientHeight * 0.8 - 150 + 'px'
w = ((document.body.clientHeight * 0.8 - 150) / 0.62548 + 40) / 0.94
}
let op = { frontColorPic: '', backColorPic: '', frontBlackPic: '', backBlackPic: '', frontData: [], backData: [], flag: 1, frontDisplayPic: url3, backDisplayPic: url4 }
if ((objs1.length != 0) & (objs2.length == 0)) {
op.flag = 2
} else if ((objs1.length == 0) & (objs2.length != 0)) {
op.flag = 3
}
op.frontColorPic = desEncrypt(url1)
op.backColorPic = desEncrypt(url2)
//op.frontBlPic = url5;
//op.backBlPic = url6;
op.frontBlackPic = desEncrypt(url5)
op.backBlackPic = desEncrypt(url6)
for (let item of _objs1) {
let idx = getIndex(item, canvas1)
if (idx == 0) continue //background-image
let type = objs1[idx - 1].type
if (type == 2) {
//out_pic
let xy = getAbsoluteXY(item)
op.frontData.push({
type: 1,
name: objs1[idx - 1].name,
FontColor: objs1[idx - 1].black ? '#000000' : '@',
transparency: item.get('opacity'),
x: parseInt((xy[0] - background_image1.left).toFixed(0)),
y: parseInt((xy[1] - background_image1.top).toFixed(0)),
h: parseInt((item.get('scaleY') * item.get('height')).toFixed(0)),
w: parseInt((item.get('scaleX') * item.get('width')).toFixed(0)),
rotate: parseInt(item.get('angle').toFixed(0))
})
} else if (type == 3) {
//text
/*2022-07-26 黑色并入黑色图层
if(item.get("fill") == "#000000"){
//纯黑
op.frontData.push({
"type" : 2,
"Text" : item.get("text"),
"FontFamily" : item.get("fontFamily"),
"FontSize" : parseInt(item.get("fontSize")),
"FontColor" : "#000000",
"FontBackgroudColor" : item.get("textBackgroundColor"),
"Bold" : item.get("fontWeight") == "bold",
"Underline" : item.get("underline"),
"Italic" : item.get("fontStyle") == "italic",
"Strikeout" : item.get("linethrough"),
"x" : parseInt((item.get("left") - background_image1.left).toFixed(0)),
"y" : parseInt((item.get("top") - background_image1.top).toFixed(0)),
"h" : parseInt((item.get("scaleY") * item.get("height")).toFixed(0)),
"w" : parseInt((item.get("scaleX") * item.get("width")).toFixed(0)),
"rotate" : parseInt(item.get("angle").toFixed(0))
});
}
*/
} else if (type == 11) {
//circle_text
op.frontData.push({
"type": 2,
"Text": item.get("text"),
"FontFamily": item.get("fontFamily"),
"FontSize": parseInt(item.get("fontSize")),
"FontColor": "#000000",
"FontBackgroudColor": item.get("textBackgroundColor"),
"Bold": item.get("fontWeight") == "bold",
"Underline": item.get("underline"),
"Italic": item.get("fontStyle") == "italic",
"Strikeout": item.get("linethrough"),
"x": parseInt((item.get("left") - background_image1.left).toFixed(0)),
"y": parseInt((item.get("top") - background_image1.top).toFixed(0)),
"h": parseInt((item.get("scaleY") * item.get("height")).toFixed(0)),
"w": parseInt((item.get("scaleX") * item.get("width")).toFixed(0)),
"rotate": parseInt(item.get("angle").toFixed(0)),
"circleCenter": objs1[idx - 1].circleCenter || 0
});
} else if (type == 4) {
//out_text
let xy = getAbsoluteXY(item)
op.frontData.push({
type: 3,
name: objs1[idx - 1].name,
FontFamily: item.get('fontFamily'),
DefaultText: item.get('text'),
FontBackgroudColor: item.get('textBackgroundColor'),
FontSize: parseInt(item.get('fontSize')),
FontColor: item.get('fill'),
Exceed: objs1[idx - 1].exceed,
AutoWrap: objs1[idx - 1].autoWrap,
FixSize: objs1[idx - 1].fixSize,
Bold: item.get('fontWeight') == 'bold',
Underline: item.get('underline'),
Italic: item.get('fontStyle') == 'italic',
Strikeout: item.get('linethrough'),
x: parseInt((xy[0] - background_image1.left).toFixed(0)),
y: parseInt((xy[1] - background_image1.top).toFixed(0)),
h: parseInt((item.get('scaleY') * item.get('height')).toFixed(0)),
w: parseInt((item.get('scaleX') * item.get('width')).toFixed(0)),
rotate: parseInt(item.get('angle').toFixed(0)),
align: objs1[idx - 1].align
})
} else if (type == 8) {
//二维码
let xy = getAbsoluteXY(item)
op.frontData.push({
type: 4,
name: objs1[idx - 1].name,
FontColor: objs1[idx - 1].color,
DefaultText: objs1[idx - 1].val,
x: parseInt((xy[0] - background_image1.left).toFixed(0)),
y: parseInt((xy[1] - background_image1.top).toFixed(0)),
h: parseInt((item.get('scaleY') * item.get('height')).toFixed(0)),
w: parseInt((item.get('scaleX') * item.get('width')).toFixed(0)),
rotate: parseInt(item.get('angle').toFixed(0))
})
} else if (type == 9) {
//条形码
let xy = getAbsoluteXY(item)
op.frontData.push({
type: 5,
name: objs1[idx - 1].name,
FontSize: parseInt(objs1[idx - 1].fontSize),
DefaultText: objs1[idx - 1].val,
HideText: objs1[idx - 1].show,
FontFamily: objs1[idx - 1].font,
FontColor: objs1[idx - 1].color,
x: parseInt((xy[0] - background_image1.left).toFixed(0)),
y: parseInt((xy[1] - background_image1.top).toFixed(0)),
h: parseInt((item.get('scaleY') * item.get('height')).toFixed(0)),
w: parseInt((item.get('scaleX') * item.get('width')).toFixed(0)),
rotate: parseInt(item.get('angle').toFixed(0))
})
} else if (type == 10) {
let xy = getAbsoluteXY(item)
op.frontData.push({
type: 6,
name: objs1[idx - 1].name,
FontFamily: item.get('fontFamily'),
FontSize: parseInt(item.get('fontSize')),
FontColor: item.get('fill'),
start: objs1[idx - 1].start,
add: parseInt(objs1[idx - 1].add),
x: parseInt((xy[0] - background_image1.left).toFixed(0)),
y: parseInt((xy[1] - background_image1.top).toFixed(0)),
h: parseInt((item.get('scaleY') * item.get('height')).toFixed(0)),
w: parseInt((item.get('scaleX') * item.get('width')).toFixed(0)),
rotate: parseInt(item.get('angle').toFixed(0))
})
}
}
//obj2
for (let item of _objs2) {
let idx = getIndex(item, canvas2)
if (idx == 0) continue //background-image
let type = objs2[idx - 1].type
if (type == 2) {
//out_pic
let xy = getAbsoluteXY(item)
op.backData.push({
type: 1,
name: objs2[idx - 1].name,
FontColor: objs2[idx - 1].black ? '#000000' : '@',
transparency: item.get('opacity'),
x: parseInt((xy[0] - background_image2.left).toFixed(0)),
y: parseInt((xy[1] - background_image2.top).toFixed(0)),
h: parseInt((item.get('scaleY') * item.get('height')).toFixed(0)),
w: parseInt((item.get('scaleX') * item.get('width')).toFixed(0)),
rotate: parseInt(item.get('angle').toFixed(0))
})
} else if (type == 3) {
//text
/*2022-07-26 黑色并入黑色图层
if(item.get("fill") == "#000000"){
//纯黑
op.backData.push({
"type" : 2,
"Text" : item.get("text"),
"FontFamily" : item.get("fontFamily"),
"FontSize" : parseInt(item.get("fontSize")),
"FontColor" : "#000000",
"FontBackgroudColor" : item.get("textBackgroundColor"),
"Bold" : item.get("fontWeight") == "bold",
"Underline" : item.get("underline"),
"Italic" : item.get("fontStyle") == "italic",
"Strikeout" : item.get("linethrough"),
"x" : parseInt((item.get("left") - background_image2.left).toFixed(0)),
"y" : parseInt((item.get("top") - background_image2.top).toFixed(0)),
"h" : parseInt((item.get("scaleY") * item.get("height")).toFixed(0)),
"w" : parseInt((item.get("scaleX") * item.get("width")).toFixed(0)),
"rotate" : parseInt(item.get("angle").toFixed(0))
});
}
*/
} else if (type == 11) {
//circle_text
op.backData.push({
"type": 2,
"Text": item.get("text"),
"FontFamily": item.get("fontFamily"),
"FontSize": parseInt(item.get("fontSize")),
"FontColor": "#000000",
"FontBackgroudColor": item.get("textBackgroundColor"),
"Bold": item.get("fontWeight") == "bold",
"Underline": item.get("underline"),
"Italic": item.get("fontStyle") == "italic",
"Strikeout": item.get("linethrough"),
"x": parseInt((item.get("left") - background_image2.left).toFixed(0)),
"y": parseInt((item.get("top") - background_image2.top).toFixed(0)),
"h": parseInt((item.get("scaleY") * item.get("height")).toFixed(0)),
"w": parseInt((item.get("scaleX") * item.get("width")).toFixed(0)),
"rotate": parseInt(item.get("angle").toFixed(0)),
"circleCenter": objs2[idx - 1].circleCenter || 0
});
} else if (type == 4) {
let xy = getAbsoluteXY(item)
op.backData.push({
type: 3,
name: objs2[idx - 1].name,
FontFamily: item.get('fontFamily'),
DefaultText: item.get('text'),
FontSize: parseInt(item.get('fontSize')),
FontBackgroudColor: item.get('textBackgroundColor'),
FontColor: item.get('fill'),
Exceed: objs2[idx - 1].exceed,
AutoWrap: objs2[idx - 1].autoWrap,
FixSize: objs2[idx - 1].fixSize,
Bold: item.get('fontWeight') == 'bold',
Underline: item.get('underline'),
Italic: item.get('fontStyle') == 'italic',
Strikeout: item.get('linethrough'),
x: parseInt((xy[0] - background_image2.left).toFixed(0)),
y: parseInt((xy[1] - background_image2.top).toFixed(0)),
h: parseInt((item.get('scaleY') * item.get('height')).toFixed(0)),
w: parseInt((item.get('scaleX') * item.get('width')).toFixed(0)),
rotate: parseInt(item.get('angle').toFixed(0)),
align: objs2[idx - 1].align
})
} else if (type == 8) {
//二维码
let xy = getAbsoluteXY(item)
op.backData.push({
type: 4,
name: objs2[idx - 1].name,
FontColor: objs2[idx - 1].color,
DefaultText: objs2[idx - 1].val,
x: parseInt((xy[0] - background_image2.left).toFixed(0)),
y: parseInt((xy[1] - background_image2.top).toFixed(0)),
h: parseInt((item.get('scaleY') * item.get('height')).toFixed(0)),
w: parseInt((item.get('scaleX') * item.get('width')).toFixed(0)),
rotate: parseInt(item.get('angle').toFixed(0))
})
} else if (type == 9) {
let xy = getAbsoluteXY(item)
op.backData.push({
type: 5,
name: objs2[idx - 1].name,
DefaultText: objs2[idx - 1].val,
HideText: objs1[idx - 1].show,
FontSize: parseInt(objs2[idx - 1].fontSize),
FontFamily: objs2[idx - 1].font,
FontColor: objs2[idx - 1].color,
x: parseInt((xy[0] - background_image2.left).toFixed(0)),
y: parseInt((xy[1] - background_image2.top).toFixed(0)),
h: parseInt((item.get('scaleY') * item.get('height')).toFixed(0)),
w: parseInt((item.get('scaleX') * item.get('width')).toFixed(0)),
rotate: parseInt(item.get('angle').toFixed(0))
})
} else if (type == 10) {
let xy = getAbsoluteXY(item)
op.backData.push({
type: 6,
name: objs2[idx - 1].name,
FontFamily: item.get('fontFamily'),
FontSize: parseInt(item.get('fontSize')),
FontColor: item.get('fill'),
start: parseInt(objs2[idx - 1].start),
add: parseInt(objs2[idx - 1].add),
x: parseInt((xy[0] - background_image2.left).toFixed(0)),
y: parseInt((xy[1] - background_image2.top).toFixed(0)),
h: parseInt((item.get('scaleY') * item.get('height')).toFixed(0)),
w: parseInt((item.get('scaleX') * item.get('width')).toFixed(0)),
rotate: parseInt(item.get('angle').toFixed(0))
})
}
}
_save(op, callback)
//return false 开启该代码可禁止点击该按钮关闭
})
})
}
$('#output').on('click', function () {
output(null, saveAs)
})
var _keyctrl = false,
_keyc = false,
_textEdit = false,
_inputEdit = false
$('input').focus(function () {
_inputEdit = true
})
$('input').blur(function () {
_inputEdit = false
})
$('textarea').focus(function () {
_inputEdit = true
})
$('textarea').blur(function () {
_inputEdit = false
})
$('body').keyup(function (event) {
// 兼容三端的 modifier key 检测(Windows/Linux: Ctrl, Mac: Cmd/Meta
if (event.keyCode == 17 || event.keyCode == 91 || event.keyCode == 93) { // Ctrl 键或 Meta 键(Mac Cmd)释放
_keyctrl = false
}
if (event.keyCode == 67) {
_keyc = false
}
})
$('body').keydown(function (event) {
// 统一的快捷键处理(兼容 Windows/Linux: Ctrl, Mac: Cmd/Meta
const isModifierKey = event.ctrlKey || event.metaKey; // 兼容三端
// 快捷键处理(在输入框或文本区域中时不触发,除了删除相关的)
if (!_inputEdit && !_textEdit) {
// CTRL/CMD+N - 新建
if (isModifierKey && event.keyCode == 78) {
event.preventDefault();
$('#new').click();
return;
}
// CTRL/CMD+O - 打开
if (isModifierKey && event.keyCode == 79) {
event.preventDefault();
$('#open').click();
return;
}
// CTRL/CMD+S - 保存
if (isModifierKey && !event.shiftKey && event.keyCode == 83) {
event.preventDefault();
$('#save').click();
return;
}
// CTRL/CMD+SHIFT+S - 保存副本
if (isModifierKey && event.shiftKey && event.keyCode == 83) {
event.preventDefault();
output(null, saveAs);
return;
}
// CTRL/CMD+Z - 还原
if (isModifierKey && !event.shiftKey && event.keyCode == 90) {
event.preventDefault();
$('#previous').click();
return;
}
// CTRL/CMD+Y - 重做
if (isModifierKey && !event.shiftKey && event.keyCode == 89) {
event.preventDefault();
$('#next').click();
return;
}
// CTRL/CMD+C - 复制
if (isModifierKey && event.keyCode == 67 && event.target.nodeName == 'BODY') {
event.preventDefault();
copySelection();
return;
}
// CTRL/CMD+V - 粘贴
if (isModifierKey && event.keyCode == 86 && event.target.nodeName == 'BODY') {
event.preventDefault();
pasteFromClipboard();
return;
}
// CTRL/CMD+SHIFT+DEL - 清空
if (isModifierKey && event.shiftKey && event.keyCode == 46) {
event.preventDefault();
$('#clean').click();
return;
}
// CTRL/CMD+DEL - 删除
if (isModifierKey && !event.shiftKey && event.keyCode == 46) {
event.preventDefault();
$('#delete').click();
return;
}
}
// 兼容三端的 modifier key 检测(Windows/Linux: Ctrl, Mac: Cmd/Meta
if (event.keyCode == 17 || event.metaKey) { // Ctrl 键或 Meta 键(Mac Cmd
_keyctrl = true
if (_keyc && _textEdit) {
//同时按下且在编辑状态
setTimeout("clipboard.writeText( (clipboard.readText()+' ') );", 1)
//clipboard.writeText((clipboard.readText()+' '))
}
}
if (event.keyCode == 67) {
_keyc = true
if (_keyctrl & _textEdit) {
//同时按下且在编辑状态
setTimeout("clipboard.writeText( (clipboard.readText()+' ') );", 1)
//clipboard.writeText((clipboard.readText()+' '))
}
}
if (event.keyCode == 37) {
//left
let v = -1
if (_keyctrl || event.ctrlKey || event.metaKey) {
v = -5
}
if (canvas.getActiveObject()) {
let x = canvas.getActiveObject().get('left')
x += v
canvas.getActiveObject().set('left', x)
canvas.renderAll()
recordState()
updateControls()
}
}
if (event.keyCode == 38) {
//up
let v = -1
if (_keyctrl || event.ctrlKey || event.metaKey) {
v = -5
}
if (canvas.getActiveObject()) {
let y = canvas.getActiveObject().get('top')
y += v
canvas.getActiveObject().set('top', y)
canvas.renderAll()
recordState()
updateControls()
}
}
if (event.keyCode == 39) {
//right
let v = 1
if (_keyctrl || event.ctrlKey || event.metaKey) {
v = 5
}
if (canvas.getActiveObject()) {
let x = canvas.getActiveObject().get('left')
x += v
canvas.getActiveObject().set('left', x)
canvas.renderAll()
recordState()
updateControls()
}
}
if (event.keyCode == 40) {
//down
let v = +1
if (_keyctrl || event.ctrlKey || event.metaKey) {
v = 5
}
if (canvas.getActiveObject()) {
let y = canvas.getActiveObject().get('top')
y += v
canvas.getActiveObject().set('top', y)
canvas.renderAll()
recordState()
updateControls()
}
}
// 普通删除键(DEL键,没有按CTRL/CMD
if (event.keyCode == 46 && !isModifierKey && !_inputEdit && !_textEdit) {
let actObjs = canvas.getActiveObjects()
let allObjs = canvas.getObjects()
let flag = 0
for (let item of actObjs) {
if (item != allObjs[0]) {
let i = getIndex(item, canvas) //0是背景,所以从1开始,但objs不包含背景图片,故要-1
objs.splice(i - 1, 1)
canvas.remove(item)
flag = 1
}
}
updateList()
canvas.discardActiveObject()
if (flag == 1) {
recordState()
canvas.renderAll()
handleObjectSelected()
}
}
})
// 复制选中对象
function copySelection() {
const activeObjects = canvas.getActiveObjects();
if (!activeObjects || activeObjects.length === 0) {
layer.msg("未选中任何对象")
return;
}
// 存储原始对象用于克隆
clipboardData.objects = activeObjects;
}
// 粘贴对象
function pasteFromClipboard() {
if (!clipboardData.objects || clipboardData.objects.length === 0) {
layer.msg("剪贴板为空")
return;
}
// 克隆所有对象
fabric.util.enlivenObjects(
clipboardData.objects.map(obj => obj.toObject()),
clonedObjects => {
// 设置新位置(添加偏移)
clonedObjects.forEach((clone, index) => {
let idx = getIndex(clipboardData.objects[index], canvas)
clone.set({
left: clone.left + clipboardData.offset,
top: clone.top + clipboardData.offset,
evented: true
});
// 添加到画布
canvas.add(clone);
let tobj = { ...objs[idx - 1] }
if (tobj.name) tobj.name = tobj.name + objs.length
objs.push(tobj);
canvas.renderAll();
updateList();
recordState();
});
// 选中粘贴的对象
canvas.discardActiveObject();
const sel = new fabric.ActiveSelection(clonedObjects, {
canvas: canvas
});
canvas.setActiveObject(sel);
canvas.requestRenderAll();
selectObj(objs.length - 1);
// 增加下次偏移
clipboardData.offset += 10;
}
);
}