cad area punti mpodifica manuale
This commit is contained in:
+490
-24
@@ -280,6 +280,15 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.manual-edit-help {
|
||||
background: #f8fafc;
|
||||
border: 1px dashed #cbd5e1;
|
||||
color: #475569;
|
||||
border-radius: 10px;
|
||||
padding: 8px 12px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@@ -467,10 +476,18 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
✅ Chiudi esclusione
|
||||
</button>
|
||||
|
||||
<button type="button" id="toolEditBtn" class="btn btn-outline-secondary">
|
||||
✋ Modifica punti
|
||||
</button>
|
||||
|
||||
<button type="button" id="undoPointBtn" class="btn btn-outline-secondary">
|
||||
↩️ Annulla punto
|
||||
</button>
|
||||
|
||||
<button type="button" id="deleteSelectedPointBtn" class="btn btn-outline-danger">
|
||||
❌ Elimina punto
|
||||
</button>
|
||||
|
||||
<button type="button" id="resetManualBtn" class="btn btn-outline-warning">
|
||||
🔄 Reset
|
||||
</button>
|
||||
@@ -562,6 +579,14 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
let polygonPoints = [];
|
||||
let currentHolePoints = [];
|
||||
let holes = [];
|
||||
|
||||
let selectedEditPoint = null;
|
||||
let isDraggingEditPoint = false;
|
||||
let editDragMoved = false;
|
||||
|
||||
const POINT_HIT_RADIUS = 12;
|
||||
const SEGMENT_HIT_RADIUS = 12;
|
||||
|
||||
let lastManualResult = null;
|
||||
|
||||
$(document).ready(function() {
|
||||
@@ -957,6 +982,10 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
currentHolePoints = [];
|
||||
holes = [];
|
||||
|
||||
selectedEditPoint = null;
|
||||
isDraggingEditPoint = false;
|
||||
editDragMoved = false;
|
||||
|
||||
lastManualResult = null;
|
||||
|
||||
document.getElementById('saveManualAreaBtn').disabled = true;
|
||||
@@ -1023,24 +1052,52 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
w: 0,
|
||||
h: 0
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentTool === 'edit') {
|
||||
selectedEditPoint = findNearestEditablePoint(pos, POINT_HIT_RADIUS);
|
||||
|
||||
if (selectedEditPoint) {
|
||||
isDraggingEditPoint = true;
|
||||
editDragMoved = false;
|
||||
updateSelectedPointPosition(pos);
|
||||
markManualResultDirty();
|
||||
redrawManualOverlay();
|
||||
updateManualPreview();
|
||||
} else {
|
||||
redrawManualOverlay();
|
||||
setManualStatus('Modifica punti: clicca un punto per selezionarlo, trascinalo per spostarlo, doppio click su un segmento per inserire un nuovo punto.');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
manualOverlayCanvas.onmousemove = function(e) {
|
||||
if (currentTool !== 'roi' || !isDrawingRoi) {
|
||||
const pos = getCanvasMousePosition(e, manualOverlayCanvas);
|
||||
|
||||
if (currentTool === 'roi' && isDrawingRoi) {
|
||||
roiRect = {
|
||||
x: Math.min(roiStartX, pos.x),
|
||||
y: Math.min(roiStartY, pos.y),
|
||||
w: Math.abs(pos.x - roiStartX),
|
||||
h: Math.abs(pos.y - roiStartY)
|
||||
};
|
||||
|
||||
redrawManualOverlay();
|
||||
return;
|
||||
}
|
||||
|
||||
const pos = getCanvasMousePosition(e, manualOverlayCanvas);
|
||||
|
||||
roiRect = {
|
||||
x: Math.min(roiStartX, pos.x),
|
||||
y: Math.min(roiStartY, pos.y),
|
||||
w: Math.abs(pos.x - roiStartX),
|
||||
h: Math.abs(pos.y - roiStartY)
|
||||
};
|
||||
|
||||
redrawManualOverlay();
|
||||
if (currentTool === 'edit' && isDraggingEditPoint && selectedEditPoint) {
|
||||
updateSelectedPointPosition(pos);
|
||||
editDragMoved = true;
|
||||
markManualResultDirty();
|
||||
redrawManualOverlay();
|
||||
updateManualPreview();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
manualOverlayCanvas.onmouseup = function() {
|
||||
@@ -1055,14 +1112,48 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
updateManualPreview();
|
||||
|
||||
if (roiRect) {
|
||||
setManualStatus('ROI definita. Ora clicca “Calibra quota” e seleziona due punti su una quota nota.');
|
||||
setManualStatus('ROI definita. Ora puoi fare “Zoom su ROI” oppure calibrare una quota nota.');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentTool === 'edit' && isDraggingEditPoint) {
|
||||
isDraggingEditPoint = false;
|
||||
|
||||
if (selectedEditPoint) {
|
||||
const label = getSelectedPointLabel(selectedEditPoint);
|
||||
|
||||
if (editDragMoved) {
|
||||
setManualStatus(`Punto spostato (${label}). Puoi calcolare di nuovo oppure continuare a modificare.`);
|
||||
} else {
|
||||
setManualStatus(`Punto selezionato (${label}). Trascinalo per spostarlo, usa “Elimina punto”, oppure doppio click su un segmento per inserire un punto.`);
|
||||
}
|
||||
}
|
||||
|
||||
editDragMoved = false;
|
||||
redrawManualOverlay();
|
||||
updateManualPreview();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
manualOverlayCanvas.onclick = function(e) {
|
||||
const pos = getCanvasMousePosition(e, manualOverlayCanvas);
|
||||
|
||||
if (currentTool === 'edit') {
|
||||
selectedEditPoint = findNearestEditablePoint(pos, POINT_HIT_RADIUS);
|
||||
redrawManualOverlay();
|
||||
|
||||
if (selectedEditPoint) {
|
||||
setManualStatus(`Punto selezionato (${getSelectedPointLabel(selectedEditPoint)}). Trascina per spostarlo o clicca “Elimina punto”.`);
|
||||
} else {
|
||||
setManualStatus('Nessun punto selezionato. Clicca vicino a un punto oppure doppio click su un segmento per aggiungerne uno.');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentTool === 'calibration') {
|
||||
handleCalibrationClick(pos);
|
||||
return;
|
||||
@@ -1078,6 +1169,30 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
manualOverlayCanvas.ondblclick = function(e) {
|
||||
if (currentTool !== 'edit') {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
const pos = getCanvasMousePosition(e, manualOverlayCanvas);
|
||||
const inserted = insertPointOnNearestSegment(pos, SEGMENT_HIT_RADIUS);
|
||||
|
||||
if (inserted) {
|
||||
markManualResultDirty();
|
||||
redrawManualOverlay();
|
||||
updateManualPreview();
|
||||
setManualStatus(`Nuovo punto inserito (${getSelectedPointLabel(selectedEditPoint)}). Ora puoi trascinarlo per rifinire il profilo.`);
|
||||
} else {
|
||||
Swal.fire({
|
||||
icon: 'info',
|
||||
title: 'Nessun segmento vicino',
|
||||
text: 'Fai doppio click vicino a una linea del contorno esterno o di una esclusione.'
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function handleCalibrationClick(pos) {
|
||||
@@ -1153,6 +1268,12 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
polygonPoints.push(pos);
|
||||
selectedEditPoint = {
|
||||
type: 'outer',
|
||||
pointIndex: polygonPoints.length - 1
|
||||
};
|
||||
|
||||
markManualResultDirty();
|
||||
redrawManualOverlay();
|
||||
updateManualPreview();
|
||||
}
|
||||
@@ -1177,9 +1298,12 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
currentHolePoints.push(pos);
|
||||
lastManualResult = null;
|
||||
document.getElementById('saveManualAreaBtn').disabled = true;
|
||||
selectedEditPoint = {
|
||||
type: 'currentHole',
|
||||
pointIndex: currentHolePoints.length - 1
|
||||
};
|
||||
|
||||
markManualResultDirty();
|
||||
redrawManualOverlay();
|
||||
updateManualPreview();
|
||||
}
|
||||
@@ -1196,9 +1320,9 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
holes.push([...currentHolePoints]);
|
||||
currentHolePoints = [];
|
||||
selectedEditPoint = null;
|
||||
|
||||
lastManualResult = null;
|
||||
document.getElementById('saveManualAreaBtn').disabled = true;
|
||||
markManualResultDirty();
|
||||
|
||||
redrawManualOverlay();
|
||||
updateManualPreview();
|
||||
@@ -1276,22 +1400,27 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
manualOverlayCtx.stroke();
|
||||
|
||||
polygonPoints.forEach(point => {
|
||||
drawPoint(point, 'rgba(22, 163, 74, 1)', 4);
|
||||
polygonPoints.forEach((point, index) => {
|
||||
const selected = isSelectedPoint('outer', null, index);
|
||||
drawPoint(point, selected ? 'rgba(245, 158, 11, 1)' : 'rgba(22, 163, 74, 1)', selected ? 7 : 4);
|
||||
|
||||
if (selected) {
|
||||
drawPointRing(point, 'rgba(245, 158, 11, 1)', 11);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function drawHoles() {
|
||||
holes.forEach(hole => {
|
||||
drawHolePolygon(hole, true);
|
||||
holes.forEach((hole, holeIndex) => {
|
||||
drawHolePolygon(hole, true, holeIndex, 'hole');
|
||||
});
|
||||
|
||||
if (currentHolePoints.length > 0) {
|
||||
drawHolePolygon(currentHolePoints, false);
|
||||
drawHolePolygon(currentHolePoints, false, null, 'currentHole');
|
||||
}
|
||||
}
|
||||
|
||||
function drawHolePolygon(points, closed) {
|
||||
function drawHolePolygon(points, closed, holeIndex = null, type = 'hole') {
|
||||
if (!points || points.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -1314,8 +1443,13 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
manualOverlayCtx.stroke();
|
||||
|
||||
points.forEach(point => {
|
||||
drawPoint(point, 'rgba(220, 38, 38, 1)', 4);
|
||||
points.forEach((point, index) => {
|
||||
const selected = isSelectedPoint(type, holeIndex, index);
|
||||
drawPoint(point, selected ? 'rgba(245, 158, 11, 1)' : 'rgba(220, 38, 38, 1)', selected ? 7 : 4);
|
||||
|
||||
if (selected) {
|
||||
drawPointRing(point, 'rgba(245, 158, 11, 1)', 11);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1326,6 +1460,296 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
manualOverlayCtx.fill();
|
||||
}
|
||||
|
||||
function drawPointRing(point, color, radius) {
|
||||
manualOverlayCtx.beginPath();
|
||||
manualOverlayCtx.arc(point.x, point.y, radius, 0, Math.PI * 2);
|
||||
manualOverlayCtx.strokeStyle = color;
|
||||
manualOverlayCtx.lineWidth = 2;
|
||||
manualOverlayCtx.stroke();
|
||||
}
|
||||
|
||||
function markManualResultDirty() {
|
||||
lastManualResult = null;
|
||||
|
||||
const saveBtn = document.getElementById('saveManualAreaBtn');
|
||||
|
||||
if (saveBtn) {
|
||||
saveBtn.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
function isSelectedPoint(type, holeIndex, pointIndex) {
|
||||
if (!selectedEditPoint) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
selectedEditPoint.type === type &&
|
||||
selectedEditPoint.pointIndex === pointIndex &&
|
||||
(
|
||||
type !== 'hole' ||
|
||||
selectedEditPoint.holeIndex === holeIndex
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function getSelectedPointLabel(selection) {
|
||||
if (!selection) {
|
||||
return 'nessun punto';
|
||||
}
|
||||
|
||||
if (selection.type === 'outer') {
|
||||
return `contorno esterno, punto ${selection.pointIndex + 1}`;
|
||||
}
|
||||
|
||||
if (selection.type === 'hole') {
|
||||
return `esclusione ${selection.holeIndex + 1}, punto ${selection.pointIndex + 1}`;
|
||||
}
|
||||
|
||||
if (selection.type === 'currentHole') {
|
||||
return `esclusione attiva, punto ${selection.pointIndex + 1}`;
|
||||
}
|
||||
|
||||
return 'punto';
|
||||
}
|
||||
|
||||
function getEditablePointList() {
|
||||
const refs = [];
|
||||
|
||||
polygonPoints.forEach((point, pointIndex) => {
|
||||
refs.push({
|
||||
type: 'outer',
|
||||
holeIndex: null,
|
||||
pointIndex: pointIndex,
|
||||
point: point
|
||||
});
|
||||
});
|
||||
|
||||
holes.forEach((hole, holeIndex) => {
|
||||
hole.forEach((point, pointIndex) => {
|
||||
refs.push({
|
||||
type: 'hole',
|
||||
holeIndex: holeIndex,
|
||||
pointIndex: pointIndex,
|
||||
point: point
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
currentHolePoints.forEach((point, pointIndex) => {
|
||||
refs.push({
|
||||
type: 'currentHole',
|
||||
holeIndex: null,
|
||||
pointIndex: pointIndex,
|
||||
point: point
|
||||
});
|
||||
});
|
||||
|
||||
return refs;
|
||||
}
|
||||
|
||||
function findNearestEditablePoint(pos, radius) {
|
||||
let best = null;
|
||||
let bestDistance = radius;
|
||||
|
||||
getEditablePointList().forEach(ref => {
|
||||
const d = distance(pos, ref.point);
|
||||
|
||||
if (d <= bestDistance) {
|
||||
bestDistance = d;
|
||||
best = {
|
||||
type: ref.type,
|
||||
holeIndex: ref.holeIndex,
|
||||
pointIndex: ref.pointIndex
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
function getPointArrayBySelection(selection) {
|
||||
if (!selection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (selection.type === 'outer') {
|
||||
return polygonPoints;
|
||||
}
|
||||
|
||||
if (selection.type === 'hole') {
|
||||
return holes[selection.holeIndex] || null;
|
||||
}
|
||||
|
||||
if (selection.type === 'currentHole') {
|
||||
return currentHolePoints;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function updateSelectedPointPosition(pos) {
|
||||
const arr = getPointArrayBySelection(selectedEditPoint);
|
||||
|
||||
if (!arr || !selectedEditPoint) {
|
||||
return;
|
||||
}
|
||||
|
||||
arr[selectedEditPoint.pointIndex] = {
|
||||
x: pos.x,
|
||||
y: pos.y
|
||||
};
|
||||
}
|
||||
|
||||
function deleteSelectedPoint() {
|
||||
if (!selectedEditPoint) {
|
||||
Swal.fire({
|
||||
icon: 'info',
|
||||
title: 'Nessun punto selezionato',
|
||||
text: 'Clicca prima un punto in modalità “Modifica punti”.'
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const arr = getPointArrayBySelection(selectedEditPoint);
|
||||
|
||||
if (!arr) {
|
||||
selectedEditPoint = null;
|
||||
redrawManualOverlay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedEditPoint.type === 'outer' && arr.length <= 3) {
|
||||
Swal.fire({
|
||||
icon: 'warning',
|
||||
title: 'Non posso eliminare',
|
||||
text: 'Il contorno esterno deve avere almeno 3 punti.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedEditPoint.type === 'hole' && arr.length <= 3) {
|
||||
Swal.fire({
|
||||
icon: 'warning',
|
||||
title: 'Non posso eliminare',
|
||||
text: 'Una esclusione chiusa deve avere almeno 3 punti. Usa “Annulla punto” in modalità esclusione per rimuovere l’intera esclusione.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
arr.splice(selectedEditPoint.pointIndex, 1);
|
||||
|
||||
selectedEditPoint = null;
|
||||
markManualResultDirty();
|
||||
redrawManualOverlay();
|
||||
updateManualPreview();
|
||||
|
||||
setManualStatus('Punto eliminato. Ricontrolla il profilo e calcola di nuovo l’area.');
|
||||
}
|
||||
|
||||
function pointToSegmentDistance(p, a, b) {
|
||||
const dx = b.x - a.x;
|
||||
const dy = b.y - a.y;
|
||||
|
||||
if (dx === 0 && dy === 0) {
|
||||
return distance(p, a);
|
||||
}
|
||||
|
||||
let t = ((p.x - a.x) * dx + (p.y - a.y) * dy) / (dx * dx + dy * dy);
|
||||
t = Math.max(0, Math.min(1, t));
|
||||
|
||||
const projection = {
|
||||
x: a.x + t * dx,
|
||||
y: a.y + t * dy
|
||||
};
|
||||
|
||||
return distance(p, projection);
|
||||
}
|
||||
|
||||
function findNearestSegment(pos, radius) {
|
||||
const candidates = [];
|
||||
|
||||
function addSegments(points, type, holeIndex, closed) {
|
||||
if (!points || points.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const limit = closed ? points.length : points.length - 1;
|
||||
|
||||
for (let i = 0; i < limit; i++) {
|
||||
const nextIndex = (i + 1) % points.length;
|
||||
|
||||
if (!closed && nextIndex === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
candidates.push({
|
||||
type: type,
|
||||
holeIndex: holeIndex,
|
||||
insertIndex: i + 1,
|
||||
a: points[i],
|
||||
b: points[nextIndex],
|
||||
distance: pointToSegmentDistance(pos, points[i], points[nextIndex])
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addSegments(polygonPoints, 'outer', null, polygonPoints.length >= 3);
|
||||
|
||||
holes.forEach((hole, holeIndex) => {
|
||||
addSegments(hole, 'hole', holeIndex, hole.length >= 3);
|
||||
});
|
||||
|
||||
addSegments(currentHolePoints, 'currentHole', null, false);
|
||||
|
||||
let best = null;
|
||||
|
||||
candidates.forEach(candidate => {
|
||||
if (candidate.distance <= radius && (!best || candidate.distance < best.distance)) {
|
||||
best = candidate;
|
||||
}
|
||||
});
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
function insertPointOnNearestSegment(pos, radius) {
|
||||
const segment = findNearestSegment(pos, radius);
|
||||
|
||||
if (!segment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let arr = null;
|
||||
|
||||
if (segment.type === 'outer') {
|
||||
arr = polygonPoints;
|
||||
} else if (segment.type === 'hole') {
|
||||
arr = holes[segment.holeIndex];
|
||||
} else if (segment.type === 'currentHole') {
|
||||
arr = currentHolePoints;
|
||||
}
|
||||
|
||||
if (!arr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
arr.splice(segment.insertIndex, 0, {
|
||||
x: pos.x,
|
||||
y: pos.y
|
||||
});
|
||||
|
||||
selectedEditPoint = {
|
||||
type: segment.type,
|
||||
holeIndex: segment.holeIndex,
|
||||
pointIndex: segment.insertIndex
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function calculateManualArea() {
|
||||
if (!mmPerPx || !calibrationMm || !calibrationPx) {
|
||||
Swal.fire({
|
||||
@@ -1589,6 +2013,10 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
parts.push(`Punti esclusione attiva: ${currentHolePoints.length}`);
|
||||
}
|
||||
|
||||
if (selectedEditPoint) {
|
||||
parts.push(`Selezionato: ${getSelectedPointLabel(selectedEditPoint)}`);
|
||||
}
|
||||
|
||||
document.getElementById('manualCoordsPreview').innerText =
|
||||
parts.length ? parts.join(' | ') : 'Nessun dato calcolato.';
|
||||
}
|
||||
@@ -1605,6 +2033,17 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
holeBtn.classList.remove('active');
|
||||
}
|
||||
|
||||
const editBtn = document.getElementById('toolEditBtn');
|
||||
if (editBtn) {
|
||||
editBtn.classList.remove('active');
|
||||
}
|
||||
|
||||
if (tool !== 'edit') {
|
||||
selectedEditPoint = null;
|
||||
isDraggingEditPoint = false;
|
||||
editDragMoved = false;
|
||||
}
|
||||
|
||||
if (tool === 'roi') {
|
||||
document.getElementById('toolRoiBtn').classList.add('active');
|
||||
|
||||
@@ -1629,6 +2068,14 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
document.getElementById('toolHoleBtn').classList.add('active');
|
||||
setManualStatus('Modalità area da escludere: clicca i punti del foro/cavità da sottrarre, poi clicca “Chiudi esclusione”.');
|
||||
}
|
||||
|
||||
if (tool === 'edit') {
|
||||
document.getElementById('toolEditBtn').classList.add('active');
|
||||
setManualStatus('Modalità modifica punti: clicca e trascina un punto per spostarlo. Doppio click su un segmento per aggiungere un punto. Usa “Elimina punto” per cancellare quello selezionato.');
|
||||
}
|
||||
|
||||
redrawManualOverlay();
|
||||
updateManualPreview();
|
||||
}
|
||||
|
||||
function setManualStatus(text) {
|
||||
@@ -1720,6 +2167,25 @@ $jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('toolEditBtn').addEventListener('click', function() {
|
||||
if (polygonPoints.length < 3 && holes.length === 0 && currentHolePoints.length === 0) {
|
||||
Swal.fire({
|
||||
icon: 'info',
|
||||
title: 'Nessun profilo da modificare',
|
||||
text: 'Disegna prima il contorno esterno oppure una esclusione.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setTool('edit');
|
||||
selectedEditPoint = null;
|
||||
redrawManualOverlay();
|
||||
});
|
||||
|
||||
document.getElementById('deleteSelectedPointBtn').addEventListener('click', function() {
|
||||
deleteSelectedPoint();
|
||||
});
|
||||
|
||||
document.getElementById('toolHoleBtn').addEventListener('click', function() {
|
||||
if (!mmPerPx) {
|
||||
Swal.fire({
|
||||
|
||||
Reference in New Issue
Block a user