Skip to content

Commit 1723197

Browse files
authored
Merge pull request #18 from brunopicinin/edit-polygon-mode
Add feature to edit polygons
2 parents 0c0479b + 59dba79 commit 1723197

File tree

3 files changed

+117
-51
lines changed

3 files changed

+117
-51
lines changed

index.html

+9-2
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,19 @@ <h2>JSON Points</h2>
7878
</span>
7979
</div>
8080
<div class="t-icon t-mode" id="mode-line">
81-
<i class="fa-solid fa-arrows-left-right"></i>
81+
<i class="fa-solid fa-lines-leaning"></i>
8282
<span class="ti-caption">
8383
<span>Line Mode</span>
8484
<span>(L)</span>
8585
</span>
8686
</div>
87+
<div class="t-icon t-mode" id="mode-edit">
88+
<i class="fa-solid fa-up-down-left-right"></i>
89+
<span class="ti-caption">
90+
<span>Edit Mode</span>
91+
<span>(E)</span>
92+
</span>
93+
</div>
8794
<div class="t-divider"></div>
8895
<div class="t-icon" id="undo">
8996
<i class="fa-solid fa-rotate-left"></i>
@@ -101,7 +108,7 @@ <h2>JSON Points</h2>
101108
</div>
102109
<div class="t-divider"></div>
103110
<div class="t-icon" id="clear">
104-
<i class="fa-solid fa-trash-can"></i>
111+
<i class="fa-solid fa-trash"></i>
105112
<span class="ti-caption">
106113
<span>Clear all polygons</span>
107114
<span>(Ctrl/⌘-E)</span>

script.js

+108-45
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ var showNormalized = false;
4242
var modeMessage = document.querySelector('#mode');
4343
// var coords = document.querySelector('#coords');
4444

45+
var editMode = false;
46+
var selectedPointIndex = -1;
47+
var selectedPolygonIndex = -1;
48+
4549
function blitCachedCanvas() {
4650
mainCtx.clearRect(0, 0, canvas.width, canvas.height);
4751
mainCtx.drawImage(offScreenCanvas, 0, 0);
@@ -185,6 +189,28 @@ function getParentPoints() {
185189
return parentPoints;
186190
}
187191

192+
function findClosestPoint(x, y) {
193+
let minDist = Infinity;
194+
let closestPoint = null;
195+
let polygonIndex = -1;
196+
let pointIndex = -1;
197+
198+
for (let i = 0; i < masterPoints.length; i++) {
199+
for (let j = 0; j < masterPoints[i].length; j++) {
200+
const [px, py] = masterPoints[i][j];
201+
const dist = Math.sqrt((x - px) ** 2 + (y - py) ** 2);
202+
if (dist < minDist && dist < 10 / scaleFactor) { // grab radius
203+
minDist = dist;
204+
closestPoint = [px, py];
205+
polygonIndex = i;
206+
pointIndex = j;
207+
}
208+
}
209+
}
210+
211+
return { point: closestPoint, polygonIndex, pointIndex };
212+
}
213+
188214
window.addEventListener('keyup', function(e) {
189215
if (e.key === 'Shift') {
190216
constrainAngles = false;
@@ -218,19 +244,16 @@ canvas.addEventListener('mouseleave', function(e) {
218244
ycoord.innerHTML = '';
219245
});
220246

221-
// on canvas hover, if cursor is crosshair, draw line from last point to cursor
222247
canvas.addEventListener('mousemove', function(e) {
223-
var x = getScaledCoords(e)[0];
224-
var y = getScaledCoords(e)[1];
225-
// round
248+
var [x, y] = getScaledCoords(e);
226249
x = Math.round(x);
227250
y = Math.round(y);
228251

229252
// update x y coords
230253
var xcoord = document.querySelector('#x');
231254
var ycoord = document.querySelector('#y');
232255

233-
if(constrainAngles) {
256+
if(constrainAngles && points.length > 0) {
234257
var lastPoint = points[points.length - 1];
235258
var dx = x - lastPoint[0];
236259
var dy = y - lastPoint[1];
@@ -258,6 +281,7 @@ canvas.addEventListener('mousemove', function(e) {
258281
ctx.lineJoin = 'bevel';
259282
ctx.fillStyle = 'white';
260283

284+
// if cursor is crosshair, draw line from last point to cursor
261285
if (canvas.style.cursor == 'crosshair') {
262286
blitCachedCanvas();
263287

@@ -284,6 +308,13 @@ canvas.addEventListener('mousemove', function(e) {
284308
drawNode(ctx, points[i][0], points[i][1]);
285309
}
286310
}
311+
312+
if (editMode && selectedPointIndex !== -1) {
313+
masterPoints[selectedPolygonIndex][selectedPointIndex] = [x, y];
314+
drawAllPolygons(offScreenCtx);
315+
blitCachedCanvas();
316+
writePoints(getParentPoints());
317+
}
287318
});
288319

289320
canvas.addEventListener('drop', function(e) {
@@ -364,57 +395,74 @@ function writePoints(parentPoints) {
364395
document.querySelector('#json').innerHTML = json_template;
365396
}
366397

367-
canvas.addEventListener('click', function(e) {
368-
canvas.style.cursor = 'crosshair';
369-
370-
var x = getScaledCoords(e)[0];
371-
var y = getScaledCoords(e)[1];
398+
canvas.addEventListener('mousedown', function(e) {
399+
var [x, y] = getScaledCoords(e);
372400
x = Math.round(x);
373401
y = Math.round(y);
374402

375-
if(constrainAngles) {
376-
var lastPoint = points[points.length - 1];
377-
var dx = x - lastPoint[0];
378-
var dy = y - lastPoint[1];
379-
var angle = Math.atan2(dy, dx);
380-
var length = Math.sqrt(dx * dx + dy * dy);
381-
const snappedAngle = Math.round(angle / radiansPer45Degrees) * radiansPer45Degrees;
382-
var new_x = lastPoint[0] + length * Math.cos(snappedAngle);
383-
var new_y = lastPoint[1] + length * Math.sin(snappedAngle);
384-
x = Math.round(new_x);
385-
y = Math.round(new_y);
386-
}
403+
if (editMode) {
404+
const { point, polygonIndex, pointIndex } = findClosestPoint(x, y);
405+
if (point) {
406+
selectedPointIndex = pointIndex;
407+
selectedPolygonIndex = polygonIndex;
408+
canvas.style.cursor = 'grabbing';
409+
}
410+
} else {
411+
// click handling for drawing mode
412+
canvas.style.cursor = 'crosshair';
413+
414+
if(constrainAngles && points.length > 0) {
415+
var lastPoint = points[points.length - 1];
416+
var dx = x - lastPoint[0];
417+
var dy = y - lastPoint[1];
418+
var angle = Math.atan2(dy, dx);
419+
var length = Math.sqrt(dx * dx + dy * dy);
420+
const snappedAngle = Math.round(angle / radiansPer45Degrees) * radiansPer45Degrees;
421+
var new_x = lastPoint[0] + length * Math.cos(snappedAngle);
422+
var new_y = lastPoint[1] + length * Math.sin(snappedAngle);
423+
x = Math.round(new_x);
424+
y = Math.round(new_y);
425+
}
387426

388-
if (points.length > 2 && drawMode == "polygon") {
389-
distX = x - points[0][0];
390-
distY = y - points[0][1];
391-
// stroke is 3px and centered on the circle (i.e. 1/2 * 3px) and arc radius is
392-
if(Math.sqrt(distX * distX + distY * distY) <= 6.5) {
393-
onPathClose();
394-
return;
427+
if (points.length > 2 && drawMode == "polygon") {
428+
distX = x - points[0][0];
429+
distY = y - points[0][1];
430+
// stroke is 3px and centered on the circle (i.e. 1/2 * 3px) and arc radius is
431+
if(Math.sqrt(distX * distX + distY * distY) <= 6.5) {
432+
onPathClose();
433+
return;
434+
}
395435
}
396-
}
397436

398-
points.push([x, y]);
437+
points.push([x, y]);
399438

400-
drawNode(mainCtx, x, y, rgb_color);
439+
drawNode(mainCtx, x, y, rgb_color);
401440

402-
if(drawMode == "line" && points.length == 2) {
403-
onPathClose();
404-
}
441+
if(drawMode == "line" && points.length == 2) {
442+
onPathClose();
443+
}
405444

406-
// concat all points into one array
407-
var parentPoints = [];
445+
// concat all points into one array
446+
var parentPoints = [];
408447

409-
for (var i = 0; i < masterPoints.length; i++) {
410-
parentPoints.push(masterPoints[i]);
411-
}
412-
// add "points"
413-
if(points.length > 0) {
414-
parentPoints.push(points);
448+
for (var i = 0; i < masterPoints.length; i++) {
449+
parentPoints.push(masterPoints[i]);
450+
}
451+
// add "points"
452+
if(points.length > 0) {
453+
parentPoints.push(points);
454+
}
455+
456+
writePoints(parentPoints);
415457
}
458+
});
416459

417-
writePoints(parentPoints);
460+
canvas.addEventListener('mouseup', function(e) {
461+
if (editMode) {
462+
selectedPointIndex = -1;
463+
selectedPolygonIndex = -1;
464+
canvas.style.cursor = 'move';
465+
}
418466
});
419467

420468
document.querySelector('#normalize-checkbox').addEventListener('change', function(e) {
@@ -425,11 +473,19 @@ document.querySelector('#normalize-checkbox').addEventListener('change', functio
425473

426474
function setDrawMode(mode) {
427475
drawMode = mode;
476+
setEditMode(false);
428477
canvas.style.cursor = 'crosshair';
429478
document.querySelectorAll('.t-mode').forEach(el => el.classList.remove('active'));
430479
document.querySelector(`#mode-${mode}`).classList.add('active');
431480
}
432481

482+
function setEditMode(editEnabled) {
483+
editMode = editEnabled;
484+
canvas.style.cursor = editEnabled ? 'move' : 'crosshair';
485+
document.querySelectorAll('.t-mode').forEach(el => el.classList.remove('active'));
486+
document.querySelector(`#mode-${editEnabled ? 'edit' : drawMode}`).classList.add('active');
487+
}
488+
433489
document.querySelector('#mode-polygon').addEventListener('click', function(e) {
434490
setDrawMode('polygon');
435491
})
@@ -438,14 +494,21 @@ document.querySelector('#mode-line').addEventListener('click', function(e) {
438494
setDrawMode('line');
439495
})
440496

497+
document.querySelector('#mode-edit').addEventListener('click', function(e) {
498+
setEditMode(true);
499+
});
500+
441501
document.addEventListener('keydown', function(e) {
442502
if (e.key == 'l' || e.key == 'L') {
443503
setDrawMode('line');
444504
}
445505
if (e.key == 'p' || e.key == 'P') {
446506
setDrawMode('polygon');
447507
}
448-
})
508+
if (e.key == 'e' || e.key == 'E') {
509+
setEditMode(true);
510+
}
511+
});
449512

450513
function rewritePoints() {
451514
var parentPoints = getParentPoints();

styles.css

-4
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,6 @@ li {
193193
margin-top: 1em;
194194
}
195195

196-
.taskbar-container .tc-container {
197-
max-width: 700px;
198-
}
199-
200196
.taskbar {
201197
display: flex;
202198
background-color: #7733f4;

0 commit comments

Comments
 (0)