Hey, I added lines!
This commit is contained in:
parent
285db679d9
commit
55f18b1cbe
1 changed files with 123 additions and 48 deletions
|
|
@ -63,6 +63,11 @@
|
||||||
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2z" />
|
<path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2z" />
|
||||||
</svg>
|
</svg>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<input type="radio" class="btn-check" id="line" name="tool">
|
||||||
|
<label for="line" class="btn btn-sm btn-light border d-inline-flex align-items-center justify-content-center">
|
||||||
|
⎯
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span id="dot" class="position-absolute p-0 m-0 d-none">
|
<span id="dot" class="position-absolute p-0 m-0 d-none">
|
||||||
|
|
@ -89,12 +94,17 @@
|
||||||
let dpr = 1;
|
let dpr = 1;
|
||||||
let selectedColor = '#000000';
|
let selectedColor = '#000000';
|
||||||
|
|
||||||
let currentRect = null;
|
let currentShape = null;
|
||||||
let rects = [];
|
let shapes = [];
|
||||||
|
|
||||||
resizeAndSetupCanvas();
|
resizeAndSetupCanvas();
|
||||||
window.addEventListener('resize', resizeAndSetupCanvas);
|
window.addEventListener('resize', resizeAndSetupCanvas);
|
||||||
|
|
||||||
|
function getActiveTool() {
|
||||||
|
const checked = document.querySelector('input[name="tool"]:checked');
|
||||||
|
return checked ? checked.id : 'outline';
|
||||||
|
}
|
||||||
|
|
||||||
function snapToGrid(x, y) {
|
function snapToGrid(x, y) {
|
||||||
const rect = gridEl.getBoundingClientRect();
|
const rect = gridEl.getBoundingClientRect();
|
||||||
const clampedX = Math.min(Math.max(x, rect.left), rect.right);
|
const clampedX = Math.min(Math.max(x, rect.left), rect.right);
|
||||||
|
|
@ -113,14 +123,20 @@
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeRect(rect) {
|
function normalizeRect(shape) {
|
||||||
|
const x = Math.min(shape.x1, shape.x2);
|
||||||
|
const y = Math.min(shape.y1, shape.y2);
|
||||||
|
const w = Math.abs(shape.x2 - shape.x1);
|
||||||
|
const h = Math.abs(shape.y2 - shape.y1);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
x: Math.min(rect.x1, rect.x2),
|
type: 'rect',
|
||||||
y: Math.min(rect.y1, rect.y2),
|
x,
|
||||||
w: Math.abs(rect.x2 - rect.x1),
|
y,
|
||||||
h: Math.abs(rect.y2 - rect.y1),
|
w,
|
||||||
color: rect.color,
|
h,
|
||||||
fill: rect.fill
|
color: shape.color,
|
||||||
|
fill: shape.fill
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -141,20 +157,29 @@
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
|
|
||||||
clearCanvas();
|
clearCanvas();
|
||||||
rects.forEach(drawRect);
|
shapes.forEach(drawShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawRect(rect) {
|
function drawShape(shape) {
|
||||||
|
if (!ctx) return;
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
ctx.strokeStyle = shape.color || '#000000';
|
||||||
|
|
||||||
ctx.strokeStyle = rect.color;
|
if (shape.type === 'rect') {
|
||||||
ctx.strokeRect(rect.x, rect.y, rect.w, rect.h);
|
ctx.strokeRect(shape.x, shape.y, shape.w, shape.h);
|
||||||
|
|
||||||
if (rect.fill) {
|
if (shape.fill) {
|
||||||
ctx.globalAlpha = 0.15;
|
ctx.globalAlpha = 0.15;
|
||||||
ctx.fillStyle = rect.color;
|
ctx.fillStyle = shape.color;
|
||||||
ctx.fillRect(rect.x, rect.y, rect.w, rect.h);
|
ctx.fillRect(shape.x, shape.y, shape.w, shape.h);
|
||||||
ctx.globalAlpha = 1;
|
ctx.globalAlpha = 1;
|
||||||
|
}
|
||||||
|
} else if ( shape.type === 'line' ) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(shape.x1, shape.y1);
|
||||||
|
ctx.lineTo(shape.x2, shape.y2);
|
||||||
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
|
|
@ -177,12 +202,12 @@
|
||||||
|
|
||||||
if ((e.ctrlKey || e.metaKey) && key === 'z') {
|
if ((e.ctrlKey || e.metaKey) && key === 'z') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
rects.pop();
|
shapes.pop();
|
||||||
redrawAll();
|
redrawAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key === 'escape' && currentRect) {
|
if (key === 'escape' && currentShape) {
|
||||||
currentRect = null;
|
currentShape = null;
|
||||||
redrawAll();
|
redrawAll();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -201,18 +226,36 @@
|
||||||
dotEl.style.top = `${renderY}px`;
|
dotEl.style.top = `${renderY}px`;
|
||||||
dotEl.style.left = `${renderX}px`;
|
dotEl.style.left = `${renderX}px`;
|
||||||
|
|
||||||
if (currentRect) {
|
if (currentShape) {
|
||||||
const previewRect = normalizeRect({
|
const tool = currentShape.tool;
|
||||||
...currentRect,
|
|
||||||
x2: snapX,
|
|
||||||
y2: snapY
|
|
||||||
});
|
|
||||||
|
|
||||||
clearCanvas();
|
clearCanvas();
|
||||||
rects.forEach(drawRect);
|
shapes.forEach(drawShape);
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
ctx.setLineDash([5, 3]);
|
ctx.setLineDash([5, 3]);
|
||||||
drawRect(previewRect);
|
|
||||||
|
if (tool === 'line') {
|
||||||
|
const previewLine = {
|
||||||
|
type: 'line',
|
||||||
|
x1: currentShape.x1,
|
||||||
|
y1: currentShape.y1,
|
||||||
|
x2: snapX,
|
||||||
|
y2: snapY,
|
||||||
|
color: currentShape.color
|
||||||
|
};
|
||||||
|
drawShape(previewLine);
|
||||||
|
} else {
|
||||||
|
const previewRect = normalizeRect({
|
||||||
|
...currentShape,
|
||||||
|
x2: snapX,
|
||||||
|
y2: snapY
|
||||||
|
});
|
||||||
|
drawShape(previewRect);
|
||||||
|
}
|
||||||
|
|
||||||
ctx.setLineDash([]);
|
ctx.setLineDash([]);
|
||||||
|
ctx.restore();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -228,34 +271,66 @@
|
||||||
|
|
||||||
if (e.target.closest('#toolBar')) return;
|
if (e.target.closest('#toolBar')) return;
|
||||||
|
|
||||||
const {ix, iy, x: snapX, y: snapY} = snapToGrid(e.clientX, e.clientY);
|
const {x: snapX, y: snapY} = snapToGrid(e.clientX, e.clientY);
|
||||||
|
const tool = getActiveTool();
|
||||||
|
|
||||||
currentRect = {
|
if (tool === 'line') {
|
||||||
x1: snapX,
|
currentShape = {
|
||||||
y1: snapY,
|
tool,
|
||||||
x2: snapX,
|
type: 'line',
|
||||||
y2: snapY,
|
x1: snapX,
|
||||||
color: selectedColor,
|
y1: snapY,
|
||||||
fill: document.getElementById('filled').checked
|
x2: snapX,
|
||||||
};
|
y2: snapY,
|
||||||
|
color: selectedColor
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
currentShape = {
|
||||||
|
tool,
|
||||||
|
x1: snapX,
|
||||||
|
y1: snapY,
|
||||||
|
x2: snapX,
|
||||||
|
y2: snapY,
|
||||||
|
color: selectedColor,
|
||||||
|
fill: document.getElementById('filled').checked
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener('mouseup', (e) => {
|
window.addEventListener('mouseup', (e) => {
|
||||||
if (!currentRect) return;
|
if (!currentShape) return;
|
||||||
|
|
||||||
const {ix, iy, x: snapX, y: snapY } = snapToGrid(e.clientX, e.clientY);
|
const { x: snapX, y: snapY } = snapToGrid(e.clientX, e.clientY);
|
||||||
|
|
||||||
currentRect.x2 = snapX;
|
currentShape.x2 = snapX;
|
||||||
currentRect.y2 = snapY;
|
currentShape.y2 = snapY;
|
||||||
|
|
||||||
const finalRect = normalizeRect(currentRect);
|
let finalShape = null;
|
||||||
|
|
||||||
if (finalRect.w > 0 && finalRect.h > 0) {
|
if (currentShape.tool === 'line') {
|
||||||
rects.push(finalRect);
|
finalShape = {
|
||||||
|
type: 'line',
|
||||||
|
x1: currentShape.x1,
|
||||||
|
y1: currentShape.y1,
|
||||||
|
x2: currentShape.x2,
|
||||||
|
y2: currentShape.y2,
|
||||||
|
color: currentShape.color
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const rect = normalizeRect(currentShape);
|
||||||
|
|
||||||
|
if (rect.w > 0 && rect.h > 0) {
|
||||||
|
finalShape = rect;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
clearCanvas();
|
|
||||||
rects.forEach(drawRect);
|
|
||||||
|
|
||||||
currentRect = null;
|
if (finalShape) {
|
||||||
|
shapes.push(finalShape);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCanvas();
|
||||||
|
shapes.forEach(drawShape);
|
||||||
|
|
||||||
|
currentShape = null;
|
||||||
});
|
});
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue