更新
This commit is contained in:
+346
-51
@@ -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();
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user