This commit is contained in:
24kycj
2025-12-06 00:26:57 +08:00
parent ff5c511eca
commit bcd5a1bd5e
4 changed files with 836 additions and 132 deletions
+346 -51
View File
@@ -15,6 +15,45 @@
height: 2787px;
border-radius: 50%;
}
/* 标尺样式 */
.ruler-container {
position: relative;
background-color: #2C2C2C;
border: 1px solid #1E1E1E;
overflow: hidden;
}
.ruler-horizontal {
position: absolute;
top: 0;
left: 0;
height: 20px;
background-color: #2C2C2C;
border-bottom: 1px solid #1E1E1E;
z-index: 1000;
}
.ruler-vertical {
position: absolute;
top: 0;
left: 0;
width: 20px;
background-color: #2C2C2C;
border-right: 1px solid #1E1E1E;
z-index: 1000;
}
.ruler-corner {
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 20px;
background-color: #2C2C2C;
border-right: 1px solid #1E1E1E;
border-bottom: 1px solid #1E1E1E;
z-index: 1001;
}
.canvas-wrapper {
position: relative;
}
</style>
</head>
@@ -195,7 +234,7 @@
</select>
</div>
<div class="component-line">
<span class="name" language="m" zh="自动圆心" ozh="自動圆心" en="Automatic center:"></span>
<span class="name" language="m" zh="中心辅助调整圆弧" ozh="中心輔助調整圓弧" en="Adjust the arc using the center:"></span>
<input type="checkbox" name="circle_text_center" id="circle_text_center" class="radio">
</div>
<div class="component-line">
@@ -575,9 +614,14 @@
</div>
<div class="right" style="background-color: #1E252D">
<div style="background-color: #1E252D;" id="canvas-div">
<div class="canvas_box">
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
<div class="canvas-wrapper">
<div class="ruler-corner"></div>
<canvas class="ruler-horizontal" id="ruler-h"></canvas>
<canvas class="ruler-vertical" id="ruler-v"></canvas>
<div class="canvas_box" style="margin-left: 20px; margin-top: 20px;">
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
</div>
</div>
<div class="canvas_bg">
<!-- 类型改变 -->
@@ -912,6 +956,10 @@
let is_bgi_add = false;
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 + ')')
@@ -3164,7 +3212,8 @@
_inputEdit = false
})
$("body").keyup(function (event) {
if (event.keyCode == 17) {
// 兼容三端的 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) {
@@ -3172,7 +3221,74 @@
};
})
$("body").keydown(function (event) {
if (event.keyCode == 17) {
// 统一的快捷键处理(兼容 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) {
//同时按下且在编辑状态
@@ -3191,7 +3307,7 @@
if (event.keyCode == 37) {
//left
let v = -1;
if (_keyctrl) {
if (_keyctrl || event.ctrlKey || event.metaKey) {
v = -5;
}
let x = canvas.getActiveObject().get("left");
@@ -3204,7 +3320,7 @@
if (event.keyCode == 38) {
//up
let v = -1;
if (_keyctrl) {
if (_keyctrl || event.ctrlKey || event.metaKey) {
v = -5;
}
let y = canvas.getActiveObject().get("top");
@@ -3217,7 +3333,7 @@
if (event.keyCode == 39) {
//right
let v = 1;
if (_keyctrl) {
if (_keyctrl || event.ctrlKey || event.metaKey) {
v = 5;
}
let x = canvas.getActiveObject().get("left");
@@ -3230,7 +3346,7 @@
if (event.keyCode == 40) {
//down
let v = +1;
if (_keyctrl) {
if (_keyctrl || event.ctrlKey || event.metaKey) {
v = 5;
}
let y = canvas.getActiveObject().get("top");
@@ -3240,25 +3356,27 @@
recordState();
updateControls();
}
if (event.keyCode != 46 || _inputEdit || _textEdit) return;
let actObjs = canvas.getActiveObjects();
let allObjs = canvas.getObjects();
let flag = 0;
for (let item of actObjs) {
if (item != allObjs[0]) {
let i = getIndex(item);//0是背景,所以从1开始,但objs不包含背景图片,故要-1
objs.splice(i - 1, 1);
canvas.remove(item);
flag = 1;
// 普通删除键(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);//0是背景,所以从1开始,但objs不包含背景图片,故要-1
objs.splice(i - 1, 1);
canvas.remove(item);
flag = 1;
}
}
updateList();
canvas.discardActiveObject();
if (flag == 1) {
recordState();
canvas.renderAll();
handleObjectSelected()
}
}
updateList();
canvas.discardActiveObject();
if (flag == 1) {
recordState();
canvas.renderAll();
handleObjectSelected()
}
});
let pre_add_image;
@@ -4211,7 +4329,9 @@
openAs.name = result.filePath;
layer.msg(language_str("saveSucc") + openAs.name);//'保存成功至'
saveHistory();
callback();
if (callback && typeof callback === 'function') {
callback();
}
}).catch(err => {
console.log()
})
@@ -4262,7 +4382,9 @@
fs.writeFileSync(openAs.name, JSON.stringify(con_o))
layer.msg(language_str("saveSucc") + openAs.name);//'保存成功至'
saveHistory();
callback();
if (callback && typeof callback === 'function') {
callback();
}
return;
}
dialog.showSaveDialog({
@@ -4281,7 +4403,9 @@
openAs.name = result.filePath;
layer.msg(language_str("saveSucc") + openAs.name);//'保存成功至'
saveHistory();
callback();
if (callback && typeof callback === 'function') {
callback();
}
}).catch(err => {
console.log()
})
@@ -6331,27 +6455,6 @@
}
updateControls();
});
// 监听键盘事件
window.addEventListener('keydown', handleKeyDown);
function handleKeyDown(e) {
// 检测 Ctrl+C
if ((e.ctrlKey || e.metaKey) && e.keyCode === 67 && e.target.nodeName == 'BODY') {
copySelection();
e.preventDefault(); // 阻止默认复制行为
}
// 检测 Ctrl+V
if ((e.ctrlKey || e.metaKey) && e.keyCode === 86 && e.target.nodeName == 'BODY') {
pasteFromClipboard();
e.preventDefault(); // 阻止默认粘贴行为
}
// 检测 Ctrl+S
if ((e.ctrlKey || e.metaKey) && e.keyCode === 83) {
output();
e.preventDefault(); // 阻止默认粘贴行为
}
}
// 复制选中对象
function copySelection() {
@@ -6997,6 +7100,198 @@
canvas.renderAll();
}
});
// 标尺绘制函数
function initRulers() {
const dpi = 600;
const mmToPx = dpi / 25.4; // 1mm = 23.622px (600 DPI)
const rulerHeight = 20;
const rulerWidth = 20;
// 获取实际画布的像素尺寸(px)
const actualCanvasWidth = canvas1.width || 2787; // 实际画布宽度(px
const actualCanvasHeight = canvas1.height || 2787; // 实际画布高度(px
// 获取显示区域的尺寸(包括 margin)
const canvasBox = $('.canvas_box');
const canvasWrapper = $('.canvas-wrapper');
// 使用 canvas-wrapper 的宽度,如果没有则使用 canvas_box + margin
let canvasWidth = canvasWrapper.width();
let canvasHeight = canvasWrapper.height();
if (!canvasWidth || canvasWidth === 0) {
canvasWidth = canvasBox.width() + 20; // 加上 margin-left: 20px
}
if (!canvasHeight || canvasHeight === 0) {
canvasHeight = canvasBox.height() + 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');
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 startX = 0;
const endX = canvasWidth;
// 绘制主要刻度(每10mm)
for (let mm = 0; mm * pxPerMm <= endX; mm += 10) {
const x = startX + 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)
for (let mm = 0; mm * pxPerMm <= endX; mm += 1) {
const x = startX + 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');
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 startY = 0;
const endY = canvasHeight;
// 绘制主要刻度(每10mm)
for (let mm = 0; mm * pxPerMm <= endY; mm += 10) {
const y = startY + 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)
for (let mm = 0; mm * pxPerMm <= endY; mm += 1) {
const y = startY + 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 canvasBox = $('.canvas_box');
const canvasWrapper = $('.canvas-wrapper');
let newWidth = canvasWrapper.width();
let newHeight = canvasWrapper.height();
if (!newWidth || newWidth === 0) {
newWidth = canvasBox.width() + 20; // 加上 margin-left: 20px
}
if (!newHeight || newHeight === 0) {
newHeight = canvasBox.height() + 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();
});
}
})
});
+490 -81
View File
@@ -7,6 +7,47 @@
<title>Soon Design</title>
<link rel="stylesheet" href="./layui/css/layui.css">
<link rel="stylesheet" href="./public/css/design.css">
<style>
/* 标尺样式 */
.ruler-container {
position: relative;
background-color: #2C2C2C;
border: 1px solid #1E1E1E;
overflow: hidden;
}
.ruler-horizontal {
position: absolute;
top: 0;
left: 0;
height: 20px;
background-color: #2C2C2C;
border-bottom: 1px solid #1E1E1E;
z-index: 1000;
}
.ruler-vertical {
position: absolute;
top: 0;
left: 0;
width: 20px;
background-color: #2C2C2C;
border-right: 1px solid #1E1E1E;
z-index: 1000;
}
.ruler-corner {
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 20px;
background-color: #2C2C2C;
border-right: 1px solid #1E1E1E;
border-bottom: 1px solid #1E1E1E;
z-index: 1001;
}
.canvas-wrapper {
position: relative;
}
</style>
</head>
<body>
@@ -193,6 +234,10 @@
style="display: inline-block;width: 150px;position: relative;top:-3px;left:5px;">
</div>
</div>
<div class="component-line">
<span class="name" language="m" zh="中心辅助调整圆弧:" ozh="中心輔助調整圓弧:" en="Adjust the arc using the center:"></span>
<input type="checkbox" name="circle_text_center" id="circle_text_center" class="radio">
</div>
<div class="component-line">
<span class="name" language="m" zh="颜色:" ozh="顏色:" en="Color:"></span>
<input type="color" id="circle_text_color" class="input_color">
@@ -554,9 +599,15 @@
</div>
<div class="right" style="background-color: #1E252D">
<div style="background-color: #1E252D;" id="canvas-div">
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
<div class="canvas-wrapper">
<div class="ruler-corner"></div>
<canvas class="ruler-horizontal" id="ruler-h"></canvas>
<canvas class="ruler-vertical" id="ruler-v"></canvas>
<div style="margin-left: 20px; margin-top: 20px;">
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
</div>
</div>
</div>
<div class="footer" style="background-color: #31373D">
<div id="posText" style="display: inline-block">X : Y : </div>
@@ -898,6 +949,9 @@
//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
// 初始化标尺
initRulers();
$('#source_front').width(zoom * $('#source_front').width())
$('#source_back').width(zoom * $('#source_back').width())
$('.canvas-container:eq(1)').hide()
@@ -1795,6 +1849,26 @@
});
}
*/
} 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)
@@ -1912,6 +1986,26 @@
});
}
*/
} 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({
@@ -2289,6 +2383,26 @@
});
}
*/
} 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)
@@ -2406,6 +2520,26 @@
});
}
*/
} 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({
@@ -2518,7 +2652,8 @@
_inputEdit = false
})
$('body').keyup(function (event) {
if (event.keyCode == 17) {
// 兼容三端的 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) {
@@ -2526,9 +2661,74 @@
}
})
$('body').keydown(function (event) {
console.log(event)
// 统一的快捷键处理(兼容 Windows/Linux: Ctrl, Mac: Cmd/Meta
const isModifierKey = event.ctrlKey || event.metaKey; // 兼容三端
if (event.keyCode == 17) {
// 快捷键处理(在输入框或文本区域中时不触发,除了删除相关的)
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) {
//同时按下且在编辑状态
@@ -2547,7 +2747,7 @@
if (event.keyCode == 37) {
//left
let v = -1
if (_keyctrl) {
if (_keyctrl || event.ctrlKey || event.metaKey) {
v = -5
}
let x = canvas.getActiveObject().get('left')
@@ -2560,7 +2760,7 @@
if (event.keyCode == 38) {
//up
let v = -1
if (_keyctrl) {
if (_keyctrl || event.ctrlKey || event.metaKey) {
v = -5
}
let y = canvas.getActiveObject().get('top')
@@ -2573,7 +2773,7 @@
if (event.keyCode == 39) {
//right
let v = 1
if (_keyctrl) {
if (_keyctrl || event.ctrlKey || event.metaKey) {
v = 5
}
let x = canvas.getActiveObject().get('left')
@@ -2586,7 +2786,7 @@
if (event.keyCode == 40) {
//down
let v = +1
if (_keyctrl) {
if (_keyctrl || event.ctrlKey || event.metaKey) {
v = 5
}
let y = canvas.getActiveObject().get('top')
@@ -2596,24 +2796,26 @@
recordState()
updateControls()
}
if (event.keyCode != 46 || _inputEdit || _textEdit) return
let actObjs = canvas.getActiveObjects()
let allObjs = canvas.getObjects()
let flag = 0
for (let item of actObjs) {
if (item != allObjs[0]) {
let i = getIndex(item) //0是背景,所以从1开始,但objs不包含背景图片,故要-1
objs.splice(i - 1, 1)
canvas.remove(item)
flag = 1
// 普通删除键(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) //0是背景,所以从1开始,但objs不包含背景图片,故要-1
objs.splice(i - 1, 1)
canvas.remove(item)
flag = 1
}
}
updateList()
canvas.discardActiveObject()
if (flag == 1) {
recordState()
canvas.renderAll()
handleObjectSelected()
}
}
updateList()
canvas.discardActiveObject()
if (flag == 1) {
recordState()
canvas.renderAll()
handleObjectSelected()
}
})
let pre_add_image
@@ -3549,7 +3751,9 @@
openAs.name = result.filePath
layer.msg(language_str('saveSucc') + openAs.name) //'保存成功至'
saveHistory()
callback()
if (callback && typeof callback === 'function') {
callback()
}
})
.catch((err) => {
console.log()
@@ -3604,7 +3808,9 @@
fs.writeFileSync(openAs.name, JSON.stringify(con_o))
layer.msg(language_str('saveSucc') + openAs.name) //'保存成功至'
saveHistory()
callback()
if (callback && typeof callback === 'function') {
callback()
}
return
}
dialog
@@ -3625,7 +3831,9 @@
openAs.name = result.filePath
layer.msg(language_str('saveSucc') + openAs.name) //'保存成功至'
saveHistory()
callback()
if (callback && typeof callback === 'function') {
callback()
}
})
.catch((err) => {
console.log()
@@ -4459,18 +4667,20 @@
text.setControlVisible("mr", false);
text.setControlVisible("mb", false);
canvas.add(text);
objs.push({ type: 11, black: false });
objs.push({ type: 11, black: false, circleCenter: 0 });
canvas.renderAll();
updateList();
recordState();
}
function selectCircleText() {
console.log(canvas.getActiveObject().get("text"))
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(canvas.getActiveObject().get("fontSize") - 10);
circle_text_diameter.setValue(canvas.getActiveObject().get("diameter")-50);
$("#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"));
@@ -5187,6 +5397,15 @@
updateList();
recordState();
})
$("#circle_text_center").click(function () {
let idx = getIndex(canvas.getActiveObject());
if ($(this).prop("checked")) {
objs[idx - 1].circleCenter = 1;
} else {
objs[idx - 1].circleCenter = 0;
}
recordState();
});
$('#out_text_color').bind('input propertychange', function () {
canvas.getActiveObject().set('fill', $('#out_text_color').val())
canvas.renderAll()
@@ -5643,44 +5862,25 @@
)
})
canvas1.on("object:moving", function (e) {
let obj = canvas.getActiveObject()
// if (objs[getIndex(e.target) - 1].type ===11) {
// let pointer = {
// x: obj.left,
// y: obj.top > canvas.height/2 ? obj.top + obj.height/2 : obj.top - obj.height/2
// }
// console.log(obj)
// 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
// obj.set("diameter", distance*2);
// obj.set("angle", angleDeg);
// obj.set("flipped", flipped);
// // canvas.renderAll();
// }
let obj = canvas1.getActiveObject()
let idx = getIndex(e.target, canvas1);
// 添加边界检查,避免访问 undefined
if (idx > 0 && idx <= objs1.length && objs1[idx - 1] && objs1[idx - 1].type && objs1[idx - 1].type === 11 && $("#circle_text_center").prop("checked")) {
let pointer = {
x: obj.left,
y: obj.top
}
let distance = getDisdance(pointer.x, pointer.y, canvas1.width/2, canvas1.height/2)
let angleDeg = getDeg(pointer)
let flipped = pointer.y > canvas1.height/2 ? true : false
circle_text_diameter.setValue(distance*2-50);
obj.set("diameter", distance*2);
obj.set("angle", angleDeg);
obj.set("flipped", flipped);
}
updateControls();
});
// 监听键盘事件
window.addEventListener('keydown', handleKeyDown);
function handleKeyDown(e) {
// 检测 Ctrl+C
if ((e.ctrlKey || e.metaKey) && e.keyCode === 67 && e.target.nodeName == 'BODY') {
copySelection();
e.preventDefault(); // 阻止默认复制行为
}
// 检测 Ctrl+V
if ((e.ctrlKey || e.metaKey) && e.keyCode === 86 && e.target.nodeName == 'BODY') {
pasteFromClipboard();
e.preventDefault(); // 阻止默认粘贴行为
}
// 检测 Ctrl+S
if ((e.ctrlKey || e.metaKey) && e.keyCode === 83) {
output();
e.preventDefault(); // 阻止默认粘贴行为
}
}
// 复制选中对象
function copySelection() {
@@ -6036,21 +6236,34 @@
$('#posText').text('X: ' + (e.pointer.x - background_image.left).toFixed(0) + ' Y: ' + (e.pointer.y - background_image.top).toFixed(0))
})
canvas2.on("object:moving", function (e) {
let obj = canvas.getActiveObject()
// if (objs[getIndex(e.target) - 1].type ===11) {
// let pointer = {
// x: obj.left,
// y: obj.top > canvas.height/2 ? obj.top + obj.height/2 : obj.top - obj.height/2
// }
// console.log(obj)
// 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
// obj.set("diameter", distance*2);
// // obj.set("angle", angleDeg);
// obj.set("flipped", flipped);
// // canvas.renderAll();
// }
let obj = canvas2.getActiveObject()
let idx = getIndex(e.target, canvas2);
// 添加边界检查,避免访问 undefined
if (idx > 0 && idx <= objs2.length && objs2[idx - 1] && objs2[idx - 1].type && objs2[idx - 1].type === 11 && $("#circle_text_center").prop("checked")) {
let pointer = {
x: obj.left,
y: obj.top
}
let distance = getDisdance(pointer.x, pointer.y, canvas2.width/2, canvas2.height/2)
// 计算角度时需要使用 canvas2
let centerX = canvas2.width / 2;
let centerY = canvas2.height / 2;
let mouseX = pointer.x;
let mouseY = pointer.y;
let dx = mouseX - centerX;
let dy = mouseY - centerY;
let angleRad = Math.atan2(dy, dx);
let angleDeg = angleRad * (180/Math.PI);
if (angleDeg < 0) {
angleDeg += 360;
}
angleDeg += 90;
let flipped = pointer.y > canvas2.height/2 ? true : false
circle_text_diameter.setValue(distance*2-50);
obj.set("diameter", distance*2);
obj.set("angle", angleDeg);
obj.set("flipped", flipped);
}
updateControls();
});
canvas2.on('object:scaling', function (e) {
@@ -6346,6 +6559,202 @@
canvas.renderAll()
}
})
// 标尺绘制函数
function initRulers() {
const dpi = 300;
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');
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 startX = 0;
const endX = canvasWidth;
// 绘制主要刻度(每10mm)
for (let mm = 0; mm * pxPerMm <= endX; mm += 10) {
const x = startX + 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)
for (let mm = 0; mm * pxPerMm <= endX; mm += 1) {
const x = startX + 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');
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 startY = 0;
const endY = canvasHeight;
// 绘制主要刻度(每10mm)
for (let mm = 0; mm * pxPerMm <= endY; mm += 10) {
const y = startY + 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)
for (let mm = 0; mm * pxPerMm <= endY; mm += 1) {
const y = startY + 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();
});
}
})
</script>
Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B