From a5b0a019dee32098d211f68250be3864836d7ab0 Mon Sep 17 00:00:00 2001 From: Leandro Rosemberg Date: Fri, 16 Aug 2024 17:53:41 -0300 Subject: [PATCH 1/9] Taskbar HTML and CSS --- index.html | 33 +++++++++++++++++++++++++++++++++ styles.css | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index f5cc6d2..6ded3fd 100644 --- a/index.html +++ b/index.html @@ -21,6 +21,9 @@ + + +
@@ -29,6 +32,36 @@

Draw points to create polygon coordinates

+
+
+
+ + Polygon Mode +
+
+ + Line Mode +
+
+
+ + Undo +
+
+ + Cancel current +
+
+
+ + Clear polygons +
+
+ + Save image +
+
+
Clear Polygons diff --git a/styles.css b/styles.css index 318673f..46a4b4c 100644 --- a/styles.css +++ b/styles.css @@ -3,7 +3,7 @@ canvas { margin: 0 auto; } * { - font-family: Arial, Helvetica, sans-serif; + font-family: Tahoma, Arial, Helvetica, sans-serif; } pre { max-height: 200px; @@ -172,6 +172,56 @@ li { margin-bottom: 4px; } +/* Taskbar */ +.taskbar-container { + display: flex; + justify-content: center; + margin-bottom: 16px; + margin-top: 32px; +} + +.taskbar { + display: flex; + background-color: #7733f4; + color: #f1edf8; + + border-radius: 5px; + width: 700px; + padding: 6px; + + justify-content:space-around; + box-shadow: 0 2px 3px 1px rgb(0 0 0 / 20%); +} + +.taskbar .t-icon { + display: flex; + flex-direction: column; + padding: 8px 24px; + border-radius: 5px; + transition: all .15s ease-in-out; +} + +.taskbar .t-icon:hover { + cursor: pointer; + background-color: #8f54fd; +} + +.taskbar .t-icon.active { + background-color: #f4efff; + color: #7733f4; +} + +.taskbar .t-icon .ti-caption { + font-size: 11px; + margin-top: 8px; +} + +.taskbar .t-divider { + background-color: #8145f1; + width: 1px; +} + + /* Helpers */ .ta-left { text-align: left; From 29011933fde39f63e8d58aa3da8709dfb16cf892 Mon Sep 17 00:00:00 2001 From: Leandro Rosemberg Date: Fri, 16 Aug 2024 18:10:51 -0300 Subject: [PATCH 2/9] Add shortcuts to taskbar --- index.html | 40 +++++++++++++++++++++++----------------- styles.css | 18 +++++++++++++++++- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/index.html b/index.html index 6ded3fd..43bb0de 100644 --- a/index.html +++ b/index.html @@ -36,34 +36,50 @@

Draw points to create polygon coordinates

- Polygon Mode + + Polygon Mode + (P) +
- Line Mode + + Line Mode + (L) +
- Undo + + Undo + (Ctrl/⌘-Z) +
- Cancel current + + Discard current + (Esc) +
- Clear polygons + + Clear all
polygons
+
- Save image + + Save image +
-
+
Clear Polygons Save Image
@@ -82,16 +98,6 @@

How to use

  • To finish, copy the numpy points to your clipboard
  • -
    -

    Keyboard shortcuts

    -
      -
    • L: Switch to line drawing mode
    • -
    • P: Swicth to polygon drawing mode
    • -
    • Enter: If you drawing a polygon, end the polygon
    • -
    • Esc: When drawing, clear the current polygon
    • -
    • Ctrl(Cmd)-Z: Undo the last point
    • -
    -

    NumPy Points

    Copy the points below into your Python code.

    Copy Python to Clipboard diff --git a/styles.css b/styles.css index 46a4b4c..09b6ced 100644 --- a/styles.css +++ b/styles.css @@ -176,7 +176,7 @@ li { .taskbar-container { display: flex; justify-content: center; - margin-bottom: 16px; + margin-bottom: 24px; margin-top: 32px; } @@ -214,6 +214,10 @@ li { .taskbar .t-icon .ti-caption { font-size: 11px; margin-top: 8px; + display: flex; + height: 100%; + flex-direction: column; + justify-content: center; } .taskbar .t-divider { @@ -237,4 +241,16 @@ li { .mb-3 { margin-bottom: 24px; +} + +.mt-1 { + margin-top: 8px; +} + +.mt-2 { + margin-top: 16px; +} + +.mt-3 { + margin-top: 24px; } \ No newline at end of file From 826aa1609187ba184a5881877b4d97105d47ee7c Mon Sep 17 00:00:00 2001 From: Leandro Rosemberg Date: Fri, 16 Aug 2024 19:18:28 -0300 Subject: [PATCH 3/9] Bind taskbar button to actions --- index.html | 26 +++---- script.js | 222 ++++++++++++++++++++++++++++++++++------------------- 2 files changed, 153 insertions(+), 95 deletions(-) diff --git a/index.html b/index.html index 43bb0de..d905fba 100644 --- a/index.html +++ b/index.html @@ -34,14 +34,14 @@

    Draw points to create polygon coordinates

    -
    +
    Polygon Mode (P)
    -
    +
    Line Mode @@ -49,14 +49,14 @@

    Draw points to create polygon coordinates

    -
    +
    Undo (Ctrl/⌘-Z)
    -
    +
    Discard current @@ -64,27 +64,23 @@

    Draw points to create polygon coordinates

    -
    +
    - Clear all
    polygons
    + Clear all polygons + (Ctrl/⌘-E)
    -
    +
    Save image + (Ctrl/⌘-S)
    -
    - Clear Polygons - Save Image -
    -

    Mode: Polygon (Press L to switch to Line drawing mode)

    -
    @@ -106,8 +102,8 @@

    NumPy Points

    - - + +
    View JSON Points diff --git a/script.js b/script.js index ba54fc3..f1b5a20 100644 --- a/script.js +++ b/script.js @@ -26,25 +26,14 @@ var regions = []; var masterPoints = []; var masterColors = []; +var drawMode +setDrawMode('polygon') + var showNormalized = false; -var drawMode = "polygon"; var modeMessage = document.querySelector('#mode'); var coords = document.querySelector('#coords'); -// if user presses L key, change draw mode to line and change cursor to cross hair -document.addEventListener('keydown', function(e) { - if (e.key == 'l') { - drawMode = "line"; - canvas.style.cursor = 'crosshair'; - modeMessage.innerHTML = "Draw Mode: Line (press p to change to polygon drawing)"; - } - if (e.key == 'p') { - drawMode = "polygon"; - canvas.style.cursor = 'crosshair'; - modeMessage.innerHTML = 'Draw Mode: Polygon (press l to change to line drawing)'; - } -}); function clipboard(selector) { var copyText = document.querySelector(selector).innerText; @@ -177,19 +166,6 @@ function getParentPoints () { return parentPoints; } -function clearall() { - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.drawImage(img, 0, 0); - points = []; - masterPoints = []; - document.querySelector('#json').innerHTML = ''; - document.querySelector('#python').innerHTML = ''; -} - -document.querySelector('#clear').addEventListener('click', function(e) { - e.preventDefault(); - clearall(); -}); document.querySelector('#clipboard').addEventListener('click', function(e) { e.preventDefault(); @@ -210,14 +186,6 @@ canvas.addEventListener('wheel', function(e) { zoom(delta); }); -document.querySelector('#saveImage').addEventListener('click', function(e) { - e.preventDefault(); - var link = document.createElement('a'); - link.download = 'image.png'; - link.href = canvas.toDataURL(); - link.click(); -}); - // on canvas hover, if cursor is crosshair, draw line from last point to cursor canvas.addEventListener('mousemove', function(e) { var x = getScaledCoords(e)[0]; @@ -240,49 +208,6 @@ canvas.addEventListener('mousemove', function(e) { -window.addEventListener('keydown', function(e) { - e.stopImmediatePropagation() - let validKey = false - - if (e.key === 'Enter') { - validKey = true - canvas.style.cursor = 'default'; - - // save current polygon points - masterPoints.push(points); - points = []; - - // dont choose a color that has already been chosen - var remaining_choices = color_choices.filter(function(x) { - return !masterColors.includes(x); - }); - - if (remaining_choices.length == 0) { - remaining_choices = color_choices; - } - - rgb_color = remaining_choices[Math.floor(Math.random() * remaining_choices.length)]; - masterColors.push(rgb_color); - } - - if (e.key === 'Escape') { - validKey = true - points = [] - } - - if (e.key === 'z' && (e.ctrlKey || e.metaKey)) { - validKey = true - points.pop() - } - - if (validKey) { - drawCurrentPolygon() - drawAllPolygons(); - var parentPoints = getParentPoints(); - writePoints(parentPoints); - } -}); - canvas.addEventListener('drop', function(e) { e.preventDefault(); var file = e.dataTransfer.files[0]; @@ -404,8 +329,145 @@ canvas.addEventListener('click', function(e) { writePoints(parentPoints); }); -document.querySelector('#normalize_checkbox').addEventListener('change', function(e) { +document.querySelector('#normalize-checkbox').addEventListener('change', function(e) { showNormalized = e.target.checked; var parentPoints = getParentPoints(); writePoints(parentPoints); -}); \ No newline at end of file +}); + +function setDrawMode(mode) { + drawMode = mode + canvas.style.cursor = 'crosshair'; + document.querySelectorAll('.t-mode').forEach(el => el.classList.remove('active')) + document.querySelector(`#mode-${mode}`).classList.add('active') +} + +document.querySelector('#mode-polygon').addEventListener('click', function(e) { + setDrawMode('polygon') +}) + +document.querySelector('#mode-line').addEventListener('click', function(e) { + setDrawMode('line') +}) + +document.addEventListener('keydown', function(e) { + if (e.key == 'l') { + setDrawMode('line') + } + if (e.key == 'p') { + setDrawMode('polygon') + } +}) + +function draw () { + drawCurrentPolygon() + drawAllPolygons() + var parentPoints = getParentPoints() + writePoints(parentPoints) +} + +function highlightButtonInteraction (buttonId) { + document.querySelector(buttonId).classList.add('active') + setTimeout(() => document.querySelector(buttonId).classList.remove('active'), 100) +} + +function undo () { + highlightButtonInteraction('#undo') + + points.pop() + draw() +} + +document.querySelector('#undo').addEventListener('click', function(e) { + undo() +}) + +function discardCurrentPolygon () { + highlightButtonInteraction('#discard-current') + + points = [] + draw() +} + +document.querySelector('#discard-current').addEventListener('click', function(e) { + discardCurrentPolygon() +}) + +function clearAll() { + highlightButtonInteraction('#clear') + + ctx.clearRect(0, 0, canvas.width, canvas.height) + ctx.drawImage(img, 0, 0) + + points = [] + masterPoints = [] + document.querySelector('#json').innerHTML = '' + document.querySelector('#python').innerHTML = '' +} + +document.querySelector('#clear').addEventListener('click', function(e) { + clearAll() +}) + +function saveImage () { + highlightButtonInteraction('#save-image') + + var link = document.createElement('a') + link.download = 'image.png' + link.href = canvas.toDataURL() + link.click() +} + +document.querySelector('#save-image').addEventListener('click', function(e) { + saveImage() +}) + +function completeCurrentPolygon () { + canvas.style.cursor = 'default' + + // save current polygon points + masterPoints.push(points) + points = [] + + // dont choose a color that has already been chosen + var remaining_choices = color_choices.filter(function(x) { + return !masterColors.includes(x) + }); + + if (remaining_choices.length == 0) { + remaining_choices = color_choices + } + + rgb_color = remaining_choices[Math.floor(Math.random() * remaining_choices.length)] + masterColors.push(rgb_color) + + draw() +} + +window.addEventListener('keydown', function(e) { + if (e.key === 'z' && (e.ctrlKey || e.metaKey)) { + e.preventDefault() + e.stopImmediatePropagation() + + undo() + } + + if (e.key === 'Escape') { + discardCurrentPolygon() + } + + if (e.key === 'e' && (e.ctrlKey || e.metaKey)) { + clearAll() + } + + if (e.key === 's' && (e.ctrlKey || e.metaKey)) { + e.preventDefault() + e.stopImmediatePropagation() + + saveImage() + } + + if (e.key === 'Enter') { + completeCurrentPolygon() + } +}) \ No newline at end of file From 3c153b492e2de5a9e8563fcede83cfd09d660209 Mon Sep 17 00:00:00 2001 From: Leandro Rosemberg Date: Fri, 16 Aug 2024 19:52:29 -0300 Subject: [PATCH 4/9] UI Adjustments: Coordinates component and image scale --- index.html | 174 +++++++++++++++++++++++++++++------------------------ script.js | 2 +- styles.css | 58 +++++++++++++----- 3 files changed, 139 insertions(+), 95 deletions(-) diff --git a/index.html b/index.html index d905fba..285da34 100644 --- a/index.html +++ b/index.html @@ -31,59 +31,68 @@

    Draw points to create polygon coordinates

    -
    -
    -
    - - - Polygon Mode - (P) - -
    -
    - - - Line Mode - (L) - -
    -
    -
    - - - Undo - (Ctrl/⌘-Z) - -
    -
    - - - Discard current - (Esc) - -
    -
    -
    - - - Clear all polygons - (Ctrl/⌘-E) - +
    +
    +
    + + + Polygon Mode + (P) + +
    +
    + + + Line Mode + (L) + +
    +
    +
    + + + Undo + (Ctrl/⌘-Z) + +
    +
    + + + Discard current + (Esc) + +
    +
    +
    + + + Clear all polygons + (Ctrl/⌘-E) + +
    +
    + + + Save image + (Ctrl/⌘-S) + +
    -
    - - - Save image - (Ctrl/⌘-S) +
    + Coordinates + + x: --- | + y: ---
    +
    -
    +

    How to use

    1. Drop an image to the indicated area
    2. @@ -94,47 +103,52 @@

      How to use

    3. To finish, copy the numpy points to your clipboard
    -

    NumPy Points

    -

    Copy the points below into your Python code.

    - Copy Python to Clipboard -
    -                        
    -                        
    -                    
    -
    - - -
    -
    - View JSON Points -

    JSON Points

    - Copy JSON to Clipboard -
    +                    
    +

    NumPy Points

    +

    Copy the points below into your Python code.

    + Copy Python to Clipboard +
                                 
                                 
                             
    -
    -
    -
    -

    Learning Resources

    -

    Browse our tutorials that walk through using PolygonZone and building projects with zones.

    -
    - Explore More Tutorials + diff --git a/script.js b/script.js index f1b5a20..d788ace 100644 --- a/script.js +++ b/script.js @@ -56,7 +56,7 @@ function zoom(clicks) { // placeholder image img.src = 'https://assets.website-files.com/5f6bc60e665f54545a1e52a5/63d3f236a6f0dae14cdf0063_drag-image-here.png'; img.onload = function() { - scaleFactor = 0.5; + scaleFactor = 0.69; canvas.style.width = img.width * scaleFactor + 'px'; canvas.style.height = img.height * scaleFactor + 'px'; canvas.width = img.width; diff --git a/styles.css b/styles.css index 09b6ced..203eb9d 100644 --- a/styles.css +++ b/styles.css @@ -50,12 +50,12 @@ main { display: flex; } .left { - flex: 0 50%; + flex: 0 60%; padding: 0 2em; border-right: 1px solid #e5e7eb; } .right { - flex: 0 50%; + flex: 0 40%; padding: 0 2em; } pre { @@ -155,17 +155,13 @@ pre { line-height: 1.4; font-weight: 400; } -.show_normalized { - background-color: #5400ec; - opacity: 0.8; - color: white; - font-weight: 600; - display: inline-block; - padding: 15px; - border-radius: 10px; -} + footer { - margin-top: 20px; + margin-top: 50px; +} + +.section { + margin-bottom: 50px; } li { @@ -175,18 +171,22 @@ li { /* Taskbar */ .taskbar-container { display: flex; - justify-content: center; + align-items: center; + flex-direction: column; margin-bottom: 24px; margin-top: 32px; } +.taskbar-container .tc-container { + width: 700px; +} + .taskbar { display: flex; background-color: #7733f4; color: #f1edf8; border-radius: 5px; - width: 700px; padding: 6px; justify-content:space-around; @@ -225,6 +225,36 @@ li { width: 1px; } +/* Coordinates */ +.coordinates { + display: flex; + flex-direction: column; + text-align: left; + + width: 130px; + padding: 8px 16px; + border-radius: 5px; + margin-top: 8px; + + font-size: 12px; + box-shadow: 0 2px 3px 1px rgb(0 0 0 / 20%); + background-color: #fbf9ff; +} + +.coordinates .cc-title { + margin-bottom: 4px; + color: #5400ec; +} + +.coordinates .cc-coord { + margin-bottom: 2px; + color: #989898; +} + +.coordinates .cc-value { + color: #000; +} + /* Helpers */ .ta-left { From 4b61d1c631577ae49b578eef4e9daa5b2c369cc3 Mon Sep 17 00:00:00 2001 From: Leandro Rosemberg Date: Fri, 16 Aug 2024 19:56:10 -0300 Subject: [PATCH 5/9] Bugfix: Prevent scroll to scroll the page --- script.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/script.js b/script.js index d788ace..9b7b4fe 100644 --- a/script.js +++ b/script.js @@ -182,6 +182,7 @@ canvas.addEventListener('dragover', function(e) { }); canvas.addEventListener('wheel', function(e) { + e.preventDefault() var delta = Math.sign(e.deltaY); zoom(delta); }); @@ -206,8 +207,6 @@ canvas.addEventListener('mousemove', function(e) { } }); - - canvas.addEventListener('drop', function(e) { e.preventDefault(); var file = e.dataTransfer.files[0]; From e227cbce09629165152b456935a30ba159ca8b3d Mon Sep 17 00:00:00 2001 From: Leandro Rosemberg Date: Fri, 16 Aug 2024 20:04:21 -0300 Subject: [PATCH 6/9] Bugfix: Wrong insertion in Line mode, don't creates the arc --- script.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/script.js b/script.js index 9b7b4fe..e2e07f4 100644 --- a/script.js +++ b/script.js @@ -301,19 +301,23 @@ return `{"x": ${point[0]}, "y": ${point[1]}}`; } canvas.addEventListener('click', function(e) { + console.log(points) // set cursor to crosshair canvas.style.cursor = 'crosshair'; - // if line mode and two points have been drawn, add to masterPoints - if (drawMode == 'line' && points.length == 2) { - masterPoints.push(points); - points = []; - } + var x = getScaledCoords(e)[0]; var y = getScaledCoords(e)[1]; x = Math.round(x); y = Math.round(y); points.push([x, y]); + + // if line mode and two points have been drawn, add to masterPoints + if (drawMode == 'line' && points.length == 2) { + masterPoints.push(points); + points = []; + } + ctx.beginPath(); ctx.strokeStyle = rgb_color; // add rgb_color to masterColors From 22adaf3cca7c74b2ad12ed5a3decfcdfa398bca8 Mon Sep 17 00:00:00 2001 From: Leandro Rosemberg Date: Fri, 16 Aug 2024 20:20:59 -0300 Subject: [PATCH 7/9] Functionality: If starting point os clicked, we complete the polygon --- script.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/script.js b/script.js index e2e07f4..fe20ded 100644 --- a/script.js +++ b/script.js @@ -301,7 +301,6 @@ return `{"x": ${point[0]}, "y": ${point[1]}}`; } canvas.addEventListener('click', function(e) { - console.log(points) // set cursor to crosshair canvas.style.cursor = 'crosshair'; @@ -310,6 +309,18 @@ canvas.addEventListener('click', function(e) { x = Math.round(x); y = Math.round(y); + // If starting point os clicked, we complete the polygon + if (drawMode === 'polygon' && points.length > 1) { + const [firstPointX, firstPointY] = points[0] + const overlapDistance = 15 + const isXOverlaped = Math.abs(x - firstPointX) <= overlapDistance + const isYOverlaped = Math.abs(y - firstPointY) <= overlapDistance + if (isXOverlaped && isYOverlaped) { + completeCurrentPolygon() + return + } + } + points.push([x, y]); // if line mode and two points have been drawn, add to masterPoints From e3adaf3b2e6a318e137ba6b49bfbbdb835749488 Mon Sep 17 00:00:00 2001 From: Leandro Rosemberg Date: Fri, 16 Aug 2024 20:26:08 -0300 Subject: [PATCH 8/9] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 257e897..17f3866 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ To use PolygonZone, open up the [PolygonZone web application](https://roboflow.g 1. Upload an image onto which you want to draw a polygon. 2. Click on the points where you want to draw the polygon. -3. Click "Enter" to save a polygon. +3. Click on the intial point or press "Enter" to save a polygon. 4. Continue to draw as many polygons as you need. 5. Copy the NumPy array or JSON object that contains the coordinates of the polygons you have drawn. From e8badbd27bcbed83ed2c054b3bc8b1151c6505ec Mon Sep 17 00:00:00 2001 From: Leandro Rosemberg Date: Mon, 19 Aug 2024 10:17:13 -0300 Subject: [PATCH 9/9] Bugfix: sometimes the main continer overflows --- index.html | 2 +- styles.css | 46 +++++++++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/index.html b/index.html index 285da34..7803320 100644 --- a/index.html +++ b/index.html @@ -111,7 +111,7 @@

    NumPy Points

    -
    +
    diff --git a/styles.css b/styles.css index 203eb9d..1960253 100644 --- a/styles.css +++ b/styles.css @@ -12,7 +12,9 @@ pre { background-color:rgba(17,24,39,0.1); padding: 10px; max-width: 100%; - overflow-x: hidden; + overflow-y: scroll; + text-wrap: wrap; + text-align: left; } body { background: rgba(17,24,39,0.4); @@ -50,34 +52,21 @@ main { display: flex; } .left { - flex: 0 60%; + flex: 60%; padding: 0 2em; border-right: 1px solid #e5e7eb; + box-sizing: border-box; } .right { - flex: 0 40%; + flex: 40%; padding: 0 2em; + box-sizing: border-box; } -pre { - text-align: left; -} -.side_by_side { - display: flex; - flex-direction: row; - align-items: flex-start; -} -.side_by_side:first-child { - flex: 0 50%; -} -.side_by_side:last-child { - flex: 0 40%; - width: 100% !important; -} -@media screen and (max-width: 1200px) { +@media screen and (max-width: 1530px) { main { padding: 3em; } - .side_by_side, .flex { + .flex { display: block; } .left, .right { @@ -86,6 +75,10 @@ pre { .left { border-right: 0; } + + canvas { + margin-bottom: 50px; + } } .controls { text-align: left; @@ -168,9 +161,20 @@ li { margin-bottom: 4px; } +.show-normalized { + background-color: #5400ec; + opacity: 0.8; + color: white; + font-weight: 600; + display: inline-block; + padding: 15px; + border-radius: 10px; +} + /* Taskbar */ .taskbar-container { display: flex; + width: 100%; align-items: center; flex-direction: column; margin-bottom: 24px; @@ -178,7 +182,7 @@ li { } .taskbar-container .tc-container { - width: 700px; + max-width: 700px; } .taskbar {