From 41a1a308fbf3652960883624edcf120762a53246 Mon Sep 17 00:00:00 2001 From: Erol444 Date: Fri, 23 Oct 2026 10:57:19 -0700 Subject: [PATCH] Redirect polygonzone.roboflow.com to the Workflows docs page PolygonZone has been replaced by the polygon zone editor in Roboflow Workflows. index.html and 404.html now send every path on the subdomain to https://docs.roboflow.com/workflows/build/draw-polygon-zones via an instant meta refresh, location.replace() and a canonical tag. The old tool's script.js and styles.css are removed; they stay in git history. Co-Authored-By: Claude Opus 5.5 --- 404.html | 14 ++ README.md | 89 +------ index.html | 159 +----------- script.js | 715 ----------------------------------------------------- styles.css | 312 ----------------------- 5 files changed, 29 insertions(+), 1260 deletions(-) create mode 100644 404.html delete mode 100644 script.js delete mode 100644 styles.css diff --git a/404.html b/404.html new file mode 100644 index 0000000..7f9f4a7 --- /dev/null +++ b/404.html @@ -0,0 +1,14 @@ + + + + + PolygonZone has moved to Roboflow Workflows + + + + + + +

PolygonZone is now part of Roboflow Workflows. If you are not redirected, go to Draw Polygon Zones and Lines.

+ + diff --git a/README.md b/README.md index 17f3866..8296387 100644 --- a/README.md +++ b/README.md @@ -1,88 +1,5 @@ -

- - - -

-
-
- - - - - - - - - - - - - - - - - - - - - - - -
-
+# PolygonZone -## About PolygonZone 📐 +PolygonZone now lives in [Roboflow Workflows](https://roboflow.com/workflows). Draw polygon zones and lines and copy their coordinates in the Workflows editor: see [Draw Polygon Zones and Lines](https://docs.roboflow.com/workflows/build/draw-polygon-zones). -PolygonZone lets you draw arbitrary polygons on an image and retrieve the coordinates of the points you have drawn. - -This application makes it easy to retrieve coordinates for Regions of Interest in computer vision applications. - -PolygonZone accompanies [Roboflow Supervision](https://github.com/roboflow/supervision), a Python library with a range of utilities that are useful in computer vision projects. - -Please note that PolygonZone is not an annotation tool. It is a tool for retrieving coordinates of polygons that you have drawn on an image. - -This application is designed for desktop use. - -## Demo - -https://user-images.githubusercontent.com/37276661/218796838-3a66a61c-ac9d-40f5-97ff-0030a8bdc60d.mov - -## Getting Started 🚀 - -To use PolygonZone, open up the [PolygonZone web application](https://roboflow.github.io/polygonzone/). Then: - -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 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. - -## Functionalities -- You can zoom in and out of an image using the mouse wheel or a laptop track pad. -- You can undo the last point pressing Ctrl/Cmd+Z -- You can discard the last unsaved polygon pressing Esc - -## Contributing 🤝 - -We welcome contributions to the PolygonZone project. Please see the [Contributing Guidelines](CONTRIBUTING.md) for more information on how you can help to improve this project. +polygonzone.roboflow.com redirects to that page. The code for the old standalone web tool is in this repository's git history. diff --git a/index.html b/index.html index 4e0655e..7f9f4a7 100644 --- a/index.html +++ b/index.html @@ -1,149 +1,14 @@ - - - - - - - PolygonZone by Roboflow - - - - - - - - - - - - - - - - - - - - -
- -
-
-
-

PolygonZone

-

PolygonZone lets you calculate polygon points in an image.

-

How to use

-
    -
  1. Drop an image to the indicated area
  2. -
  3. Select the desired mode: Press L to draw a line, or P to draw a polygon
  4. -
  5. Click to draw polygon points. Press enter to finish the polygon.
  6. -
-

Coordinates

-

Copy the points below, formatted as NumPy arrays, into your Python code.

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

JSON Points

- Copy JSON to Clipboard -
-                                
-                                
-                            
-
-
-
-
-
-
-
-
- - - Polygon Mode - (P) - -
-
- - - Line Mode - (L) - -
-
- - - Edit Mode - (E) - -
-
-
- - - Undo - (Ctrl/⌘-Z) - -
-
- - - Discard current - (Esc) - -
-
- - - Clear all polygons - (Ctrl/⌘-E) - -
-
-
- - - Save image - (Ctrl/⌘-S) - -
-
- - - Fullscreen - (F) - -
-
-
- Coordinates - - x: --- | - y: --- - -
-
-
-
- -
-
-
-
- - + + + + PolygonZone has moved to Roboflow Workflows + + + + + + +

PolygonZone is now part of Roboflow Workflows. If you are not redirected, go to Draw Polygon Zones and Lines.

+ diff --git a/script.js b/script.js deleted file mode 100644 index 5e068b3..0000000 --- a/script.js +++ /dev/null @@ -1,715 +0,0 @@ -var color_choices = [ - "#FF00FF", - "#8622FF", - "#FE0056", - "#00FFCE", - "#FF8000", - "#00B7EB", - "#FFFF00", - "#0E7AFE", - "#FFABAB", - "#0000FF", - "#CCCCCC", -]; -// if you want choices to be kind of random, shuffle the array once here - -var radiansPer45Degrees = Math.PI / 4; - -var imageContainer = document.querySelector('.image-container'); -var canvas = document.getElementById('canvas'); -var mainCtx = canvas.getContext('2d'); -var offScreenCanvas = document.createElement('canvas'); -var offScreenCtx = offScreenCanvas.getContext('2d'); -offScreenCanvas.width = canvas.width; -offScreenCanvas.height = canvas.height; - -var img = new Image(); -var rgb_color = color_choices[0]; -var fill_color = 'rgba(0,0,0,0.35)'; - -var scaleFactor = 1; -var scaleSpeed = 0.01; - -var points = []; -var masterPoints = []; -var masterColors = []; - -var drawMode; -setDrawMode('polygon'); -var constrainAngles = false; -var showNormalized = false; - -function resetState() { - points = []; - masterPoints = []; - masterColors = []; - rgb_color = color_choices[0]; - document.querySelector('#json').innerHTML = ''; - document.querySelector('#python').innerHTML = ''; -} - - -var isFullscreen = false; -var taskbarAndCanvas = document.querySelector('.right'); - -var editMode = false; -var selectedPointIndex = -1; -var selectedPolygonIndex = -1; - - -function blitCachedCanvas() { - mainCtx.clearRect(0, 0, canvas.width, canvas.height); - mainCtx.drawImage(offScreenCanvas, 0, 0); -} - -function clipboard(selector) { - var copyText = document.querySelector(selector).innerText; - // strip whitespace on left and right - copyText = copyText.replace(/^\s+|\s+$/g, ''); - navigator.clipboard.writeText(copyText); -} - -function clearDrawings() { - offScreenCtx.clearRect(0, 0, offScreenCanvas.width, offScreenCanvas.height); - blitCachedCanvas(); -} - -function isClockwise(vertices) { - let sum = 0; - for (let i = 0; i < vertices.length; i++) { - const [x1, y1] = vertices[i]; - const [x2, y2] = vertices[(i + 1) % vertices.length]; - sum += (x2 - x1) * (y2 + y1); - } - return sum > 0; -} - -function zoom(clicks) { - var newScaleFactor = scaleFactor + clicks * scaleSpeed; - newScaleFactor = Math.max(0.1, Math.min(newScaleFactor, 1)); - - const maxWidth = imageContainer.offsetWidth * 0.95; - const maxHeight = imageContainer.offsetHeight * 0.95; - - let newWidth = img.width * newScaleFactor; - let newHeight = img.height * newScaleFactor; - - if (newWidth > maxWidth) { - newHeight = (maxWidth / newWidth) * newHeight; - newWidth = maxWidth; - newScaleFactor = newWidth / img.width; - } - - if (newHeight > maxHeight) { - newWidth = (maxHeight / newHeight) * newWidth; - newHeight = maxHeight; - newScaleFactor = newHeight / img.height; - } - - scaleFactor = newScaleFactor; - canvas.style.width = newWidth + 'px'; - canvas.style.height = newHeight + 'px'; -} - -function onPathClose() { - canvas.style.cursor = 'default'; - // we do this to avoid clearing overlapping polygons - if (isClockwise(points)) { - points = points.reverse(); - } - masterPoints.push(points); - points = []; - masterColors.push(rgb_color); - drawAllPolygons(offScreenCtx); - blitCachedCanvas(); - rgb_color = color_choices[(masterColors.length) % (color_choices.length)]; -} - -// placeholder image -img.src = 'https://assets.website-files.com/5f6bc60e665f54545a1e52a5/63d3f236a6f0dae14cdf0063_drag-image-here.png'; -img.onload = function() { - scaleFactor = 0.69; - canvas.style.width = img.width * scaleFactor + 'px'; - canvas.style.height = img.height * scaleFactor + 'px'; - canvas.width = img.width; - canvas.height = img.height; - offScreenCanvas.width = img.width; - offScreenCanvas.height = img.height; - offScreenCtx.drawImage(img, 0, 0); - blitCachedCanvas(); -}; - -function makeLine(ctx, x1, y1, x2, y2) { - ctx.moveTo(x1, y1); - ctx.lineTo(x2, y2); -} - -function drawNode(ctx, x, y, stroke = null) { - if (stroke) { - ctx.strokeStyle = stroke; - } - ctx.beginPath(); - ctx.arc(x, y, 5, 0, 2 * Math.PI); - ctx.closePath(); - ctx.fillStyle = 'white'; - ctx.fill(); - ctx.stroke(); -} - -function getScaledCoords(e) { - var rect = canvas.getBoundingClientRect(); - var x = e.clientX - rect.left; - var y = e.clientY - rect.top; - return [x / scaleFactor, y / scaleFactor]; -} - -function drawAllPolygons(ctx) { - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.drawImage(img, 0, 0); - // draw polygons as subpaths and fill all at once - // we do this to avoid overlapping polygons becoming opaque - ctx.beginPath(); - ctx.fillStyle = fill_color; - for (var i = 0; i < masterPoints.length; i++) { - var newpoints = masterPoints[i]; - for (var j = 1; j < newpoints.length; j++) { - makeLine(ctx, newpoints[j - 1][0], newpoints[j - 1][1], newpoints[j][0], newpoints[j][1]); - ctx.moveTo(newpoints[0][0], newpoints[0][1]); - for (var j = 1; j < newpoints.length; j++) { - ctx.lineTo(newpoints[j][0], newpoints[j][1]); - } - makeLine(ctx, newpoints[newpoints.length - 1][0], newpoints[newpoints.length - 1][1], newpoints[0][0], newpoints[0][1]); - } - } - ctx.fill(); - - ctx.lineWidth = 5; - ctx.lineJoin = 'bevel'; - for (var i = 0; i < masterPoints.length; i++) { - var newpoints = masterPoints[i]; - ctx.strokeStyle = masterColors[i]; - - ctx.beginPath(); - for (var j = 1; j < newpoints.length; j++) { - makeLine(ctx, newpoints[j - 1][0], newpoints[j - 1][1], newpoints[j][0], newpoints[j][1]); - ctx.moveTo(newpoints[0][0], newpoints[0][1]); - for (var j = 1; j < newpoints.length; j++) { - ctx.lineTo(newpoints[j][0], newpoints[j][1]); - } - } - ctx.closePath(); - ctx.stroke(); - - // draw arc around each point - for (var j = 0; j < newpoints.length; j++) { - drawNode(ctx, newpoints[j][0], newpoints[j][1]); - } - } -} - -function getParentPoints() { - var parentPoints = []; - for (var i = 0; i < masterPoints.length; i++) { - parentPoints.push(masterPoints[i]); - } - parentPoints.push(points); - return parentPoints; -} - -function findClosestPoint(x, y) { - let minDist = Infinity; - let closestPoint = null; - let polygonIndex = -1; - let pointIndex = -1; - - for (let i = 0; i < masterPoints.length; i++) { - for (let j = 0; j < masterPoints[i].length; j++) { - const [px, py] = masterPoints[i][j]; - const dist = Math.sqrt((x - px) ** 2 + (y - py) ** 2); - if (dist < minDist && dist < 10 / scaleFactor) { // grab radius - minDist = dist; - closestPoint = [px, py]; - polygonIndex = i; - pointIndex = j; - } - } - } - - return { point: closestPoint, polygonIndex, pointIndex }; -} - -window.addEventListener('keyup', function(e) { - if (e.key === 'Shift') { - constrainAngles = false; - } -}); - -document.querySelector('#copyPythonButton').addEventListener('click', function(e) { - e.preventDefault(); - clipboard("#python"); -}); - -document.querySelector('#copyJSONButton').addEventListener('click', function(e) { - e.preventDefault(); - clipboard("#json"); -}); - -canvas.addEventListener('dragover', function(e) { - e.preventDefault(); -}); - -canvas.addEventListener('wheel', function(e) { - e.preventDefault() - var delta = Math.sign(e.deltaY); - zoom(delta); -}); - -canvas.addEventListener('mouseleave', function(e) { - var xcoord = document.querySelector('#x'); - var ycoord = document.querySelector('#y'); - xcoord.innerHTML = ''; - ycoord.innerHTML = ''; -}); - -canvas.addEventListener('mousemove', function(e) { - var [x, y] = getScaledCoords(e); - x = Math.round(x); - y = Math.round(y); - - // update x y coords - var xcoord = document.querySelector('#x'); - var ycoord = document.querySelector('#y'); - - if(constrainAngles && points.length > 0) { - var lastPoint = points[points.length - 1]; - var dx = x - lastPoint[0]; - var dy = y - lastPoint[1]; - var angle = Math.atan2(dy, dx); - var length = Math.sqrt(dx * dx + dy * dy); - const snappedAngle = Math.round(angle / radiansPer45Degrees) * radiansPer45Degrees; - var new_x = lastPoint[0] + length * Math.cos(snappedAngle); - var new_y = lastPoint[1] + length * Math.sin(snappedAngle); - x = Math.round(new_x); - y = Math.round(new_y); - } - - // sometimes, a mousemove event is leaving the canvas and has coordinates outside the canvas - // however, due to the cursors being used, we do not need to check if it is larger than canvas.width or canvas.height - if (x < 0 || y < 0 ){ - xcoord.innerHTML = ''; - ycoord.innerHTML = ''; - return; - } - xcoord.innerHTML = x; - ycoord.innerHTML = y; - - var ctx = mainCtx; - ctx.lineWidth = 5; - ctx.lineJoin = 'bevel'; - ctx.fillStyle = 'white'; - - // if cursor is crosshair, draw line from last point to cursor - if (canvas.style.cursor == 'crosshair') { - blitCachedCanvas(); - - for (var i = 0; i < points.length - 1; i++) { - ctx.strokeStyle = rgb_color; - ctx.beginPath(); - ctx.lineJoin = 'bevel'; - makeLine(ctx, points[i][0], points[i][1], points[i + 1][0], points[i + 1][1]); - ctx.closePath(); - ctx.stroke(); - - drawNode(ctx, points[i][0], points[i][1]); - } - - - if ((points.length > 0 && drawMode == "polygon") || (points.length > 0 && points.length < 2 && drawMode == "line")) { - ctx.beginPath(); - ctx.lineJoin = 'bevel'; - ctx.strokeStyle = rgb_color; - makeLine(ctx, points[points.length - 1][0], points[points.length - 1][1], x, y); - ctx.closePath(); - ctx.stroke(); - - drawNode(ctx, points[i][0], points[i][1]); - } - } - - if (editMode && selectedPointIndex !== -1) { - masterPoints[selectedPolygonIndex][selectedPointIndex] = [x, y]; - drawAllPolygons(offScreenCtx); - blitCachedCanvas(); - writePoints(getParentPoints()); - } -}); - -canvas.addEventListener('drop', function(e) { - e.preventDefault(); - var file = e.dataTransfer.files[0]; - - // only allow image files - var supportedImageTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/webp']; - if (!supportedImageTypes.includes(file.type)) { - alert('Only PNG, JPEG, JPG, and WebP files are allowed.'); - return; - } - - var reader = new FileReader(); - reader.onload = function(event) { - img.src = event.target.result; - }; - reader.readAsDataURL(file); - - img.onload = function() { - // reset state to initial values - resetState(); - - // draw loaded image on canvas - scaleFactor = 0.25; - canvas.style.width = img.width * scaleFactor + 'px'; - canvas.style.height = img.height * scaleFactor + 'px'; - canvas.width = img.width; - canvas.height = img.height; - offScreenCanvas.width = img.width; - offScreenCanvas.height = img.height; - - const maxWidth = imageContainer.offsetWidth * 0.95; - const maxHeight = imageContainer.offsetHeight * 0.95; - - let newWidth = img.width; - let newHeight = img.height; - - if (newWidth > maxWidth) { - newHeight = (maxWidth / newWidth) * newHeight; - newWidth = maxWidth; - } - - if (newHeight > maxHeight) { - newWidth = (maxHeight / newHeight) * newWidth; - newHeight = maxHeight; - } - - scaleFactor = newWidth / img.width; - - canvas.style.width = newWidth + 'px'; - canvas.style.height = newHeight + 'px'; - canvas.style.borderRadius = '10px'; - offScreenCtx.drawImage(img, 0, 0); - blitCachedCanvas(); - }; -}); - -function writePoints(parentPoints) { - var normalized = []; - - // if normalized is true, normalize all points - var imgHeight = img.height; - var imgWidth = img.width; - if (showNormalized) { - for (var i = 0; i < parentPoints.length; i++) { - var normalizedPoints = []; - for (var j = 0; j < parentPoints[i].length; j++) { - normalizedPoints.push([ - Math.round(parentPoints[i][j][0] / imgWidth * 100) / 100, - Math.round(parentPoints[i][j][1] / imgHeight * 100) / 100 - ]); - } - normalized.push(normalizedPoints); - } - parentPoints = normalized; - } - - // clean empty points - parentPoints = parentPoints.filter(points => !!points.length); - - if (!parentPoints.length) { - document.querySelector('#python').innerHTML = ''; - document.querySelector('#json').innerHTML; - return; - } - - // create np.array list - var code_template = `[\n${parentPoints.map(function(points) { - return ` np.array([${points.map(function(point) { - return `[${point[0]}, ${point[1]}]`;}).join(', ')}])`; - }).join(',\n')}\n]`; - - document.querySelector('#python').innerHTML = code_template; - - var json_template = `{\n${parentPoints.map(function(points) { - return ` [${points.map(function(point) { - return `{"x": ${point[0]}, "y": ${point[1]}}`;}).join(', ')}]`; - }).join(',\n')}\n}`; - - document.querySelector('#json').innerHTML = json_template; -} - -canvas.addEventListener('mousedown', function(e) { - var [x, y] = getScaledCoords(e); - x = Math.round(x); - y = Math.round(y); - - if (editMode) { - const { point, polygonIndex, pointIndex } = findClosestPoint(x, y); - if (point) { - selectedPointIndex = pointIndex; - selectedPolygonIndex = polygonIndex; - canvas.style.cursor = 'grabbing'; - } - } else { - // click handling for drawing mode - canvas.style.cursor = 'crosshair'; - - if(constrainAngles && points.length > 0) { - var lastPoint = points[points.length - 1]; - var dx = x - lastPoint[0]; - var dy = y - lastPoint[1]; - var angle = Math.atan2(dy, dx); - var length = Math.sqrt(dx * dx + dy * dy); - const snappedAngle = Math.round(angle / radiansPer45Degrees) * radiansPer45Degrees; - var new_x = lastPoint[0] + length * Math.cos(snappedAngle); - var new_y = lastPoint[1] + length * Math.sin(snappedAngle); - x = Math.round(new_x); - y = Math.round(new_y); - } - - if (points.length > 2 && drawMode == "polygon") { - distX = x - points[0][0]; - distY = y - points[0][1]; - // stroke is 3px and centered on the circle (i.e. 1/2 * 3px) and arc radius is - if(Math.sqrt(distX * distX + distY * distY) <= 6.5) { - onPathClose(); - return; - } - } - - points.push([x, y]); - - drawNode(mainCtx, x, y, rgb_color); - - if(drawMode == "line" && points.length == 2) { - onPathClose(); - } - - // concat all points into one array - var parentPoints = []; - - for (var i = 0; i < masterPoints.length; i++) { - parentPoints.push(masterPoints[i]); - } - // add "points" - if(points.length > 0) { - parentPoints.push(points); - } - - writePoints(parentPoints); - } -}); - -canvas.addEventListener('mouseup', function(e) { - if (editMode) { - selectedPointIndex = -1; - selectedPolygonIndex = -1; - canvas.style.cursor = 'move'; - } -}); - -document.querySelector('#normalize-checkbox').addEventListener('change', function(e) { - showNormalized = e.target.checked; - var parentPoints = getParentPoints(); - writePoints(parentPoints); -}); - -function setDrawMode(mode) { - drawMode = mode; - setEditMode(false); - canvas.style.cursor = 'crosshair'; - document.querySelectorAll('.t-mode').forEach(el => el.classList.remove('active')); - document.querySelector(`#mode-${mode}`).classList.add('active'); -} - -function setEditMode(editEnabled) { - editMode = editEnabled; - canvas.style.cursor = editEnabled ? 'move' : 'crosshair'; - document.querySelectorAll('.t-mode').forEach(el => el.classList.remove('active')); - document.querySelector(`#mode-${editEnabled ? 'edit' : drawMode}`).classList.add('active'); -} - -document.querySelector('#mode-polygon').addEventListener('click', function(e) { - setDrawMode('polygon'); -}) - -document.querySelector('#mode-line').addEventListener('click', function(e) { - setDrawMode('line'); -}) - -document.querySelector('#mode-edit').addEventListener('click', function(e) { - setEditMode(true); -}); - -document.addEventListener('keydown', function(e) { - if (e.key == 'l' || e.key == 'L') { - setDrawMode('line'); - } - if (e.key == 'p' || e.key == 'P') { - setDrawMode('polygon'); - } - if (e.key == 'e' || e.key == 'E') { - setEditMode(true); - } -}); - -function rewritePoints() { - 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'); - - if (points.length > 0) { - points.pop(); - blitCachedCanvas(); - rewritePoints(); - - if(points.length === 0){ - return; - } - - var ctx = mainCtx; - ctx.strokeStyle = rgb_color; - ctx.fillStyle = 'white'; - if (points.length === 1) { - drawNode(ctx, points[0][0], points[0][1]); - } - else { - drawNode(ctx, points[0][0], points[0][1]); - for (var i = 0; i < points.length - 1; i++) { - makeLine(ctx, points[i][0], points[i][1], points[i + 1][0], points[i + 1][1]); - ctx.stroke(); - drawNode(ctx, points[i + 1][0], points[i + 1][1]); - } - } - } -} - -document.querySelector('#undo').addEventListener('click', function(e) { - undo(); -}) - -function discardCurrentPolygon () { - highlightButtonInteraction('#discard-current'); - points = []; - blitCachedCanvas(); - rewritePoints(); -} - -document.querySelector('#discard-current').addEventListener('click', function(e) { - discardCurrentPolygon(); -}) - -function clearAll() { - highlightButtonInteraction('#clear') - resetState(); - // reset main and offscreen canvases - mainCtx.clearRect(0, 0, canvas.width, canvas.height); - offScreenCtx.clearRect(0, 0, offScreenCanvas.width, offScreenCanvas.height); - mainCtx.drawImage(img, 0, 0); - offScreenCtx.drawImage(img, 0, 0); - points = []; - masterPoints = []; - masterColors = []; - rgb_color = color_choices[0]; - document.querySelector('#jsonCode').innerHTML = ''; - document.querySelector('#pythonCode').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 toggleFullscreen() { - highlightButtonInteraction('#fullscreen'); - - if (!isFullscreen) { - if (taskbarAndCanvas.requestFullscreen) { - taskbarAndCanvas.requestFullscreen(); - } else if (taskbarAndCanvas.webkitRequestFullscreen) { // Safari - taskbarAndCanvas.webkitRequestFullscreen(); - } else if (taskbarAndCanvas.msRequestFullscreen) { // IE/Edge - taskbarAndCanvas.msRequestFullscreen(); - } - } else { - if (document.exitFullscreen) { - document.exitFullscreen(); - } else if (document.webkitExitFullscreen) { // Safari - document.webkitExitFullscreen(); - } else if (document.msExitFullscreen) { // IE/Edge - document.msExitFullscreen(); - } - } -} - -document.addEventListener('fullscreenchange', function() { - isFullscreen = document.fullscreenElement !== null; -}); - -document.querySelector('#fullscreen').addEventListener('click', function(e) { - toggleFullscreen(); -}); - -window.addEventListener('keydown', function(e) { - if (e.key === 'z' && (e.ctrlKey || e.metaKey)) { - e.preventDefault(); - e.stopImmediatePropagation(); - undo(); - } - - if (e.key === 'Shift') { - constrainAngles = true; - } - - 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') { - if(points.length > 2) { - onPathClose(); - } - } - - if (e.key === 'f' || e.key === 'F') { - toggleFullscreen(); - } -}) \ No newline at end of file diff --git a/styles.css b/styles.css deleted file mode 100644 index 2df8a20..0000000 --- a/styles.css +++ /dev/null @@ -1,312 +0,0 @@ -canvas { - display: block; - margin: 0 auto; -} -* { - font-family: Tahoma, Arial, Helvetica, sans-serif; -} -pre { - max-height: 200px; - overflow: auto; - height: 200px; - background-color:rgba(17,24,39,0.1); - padding: 10px; - max-width: 100%; - overflow-y: scroll; - text-wrap: wrap; - text-align: left; -} -body { - background: white; - height: 100vh; - margin: 0; - padding: 0; -} -main { - display: flex; - flex-direction: column; - height: 100vh; - margin: 0; - padding: 0; -} -h1 { - font-size: 28px; -} -h1, h2 { - color: rgb(103, 6, 206); -} -details { - width: 100%; - margin: 0; - text-align: left; -} -nav { - border-bottom: 1px solid lightgrey; - display: flex; - justify-content: space-between; -} -nav ul { - list-style-type: none; - padding: 0; - padding-left: 1em; -} -nav ul li { - display: inline; - margin-right: 10px; -} -summary { - border: 2px solid #00ffce; - color: #000; - padding: 10px; - margin-bottom: 10px; - border-radius: 10px; -} -a { - color: #5400ec; - text-decoration: none; -} -.content { - display: flex; - flex-grow: 1; -} -.left { - flex: 40%; - padding: 0 1em; - border-right: 1px solid #e5e7eb; - box-sizing: border-box; -} -.right { - flex: 60%; - padding: 0 2em; - box-sizing: border-box; - display: flex; - flex-direction: column; -} -.image-container { - flex-grow: 1; -} -@media screen and (max-width: 900px) { - .content { - display: block; - } - .left, .right { - padding: 0; - } - .left { - border-right: 0; - } - - canvas { - margin-bottom: 50px; - } - .right { - width: 45em; - margin: auto; - } -} -.controls { - text-align: left; -} -.space { - padding-left: 50px; -} -.widgetButton { - display: inline-block; - margin-right: 8px; - margin-left: 8px; - padding: 12px 24px; - -webkit-align-self: center; - -ms-flex-item-align: center; - -ms-grid-row-align: center; - align-self: center; - border-radius: 4px; - background-color: #7733f4; - box-shadow: 0 3px 3px 0 rgb(55 65 81 / 20%); - font-family: proxima-nova,sans-serif; - color: #fff; - font-weight: 700; - text-align: center; - letter-spacing: .5px; -} -.banner { - max-width: 100%; - margin-bottom: 20px; - max-height: 150px; -} -.grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - grid-gap: 20px; - margin-top: 30px; - max-width: 40em; - margin: auto; - margin-bottom: 30px; -} -.card { - background: #fff; - border-radius: 5px; - box-shadow: 0 2px 3px 1px rgb(0 0 0 / 10%); - overflow: hidden; - text-align: left; - padding: 10px; -} -.card img { - width: 100%; -} -.card h4 { - margin-bottom: 20px; - color: #1f2937; - font-size: 24px; - line-height: 1.2; - font-weight: 600; -} -.card a { - color: inherit; - text-decoration: none; -} -.card p { - margin-bottom: 20px; - padding-top: 10px; - border-top: 1px solid #e5e7eb; - color: #666; - line-height: 1.4; - font-weight: 400; -} - -footer { - margin-top: 50px; -} - -.section { - margin-bottom: 50px; -} - -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: 1em; - margin-top: 1em; -} - -.taskbar { - display: flex; - background-color: #7733f4; - color: #f1edf8; - - border-radius: 5px; - 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; - display: flex; - height: 100%; - flex-direction: column; - justify-content: center; -} - -.taskbar .t-divider { - background-color: #8145f1; - width: 1px; -} - -/* Coordinates */ -.coordinates { - display: flex; - flex-direction: column; - text-align: left; - - width: 100%; - box-sizing: border-box; - text-align: center; - padding: 8px 16px; - border-radius: 5px; - margin-top: 8px; - - font-size: 1em; - 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 { - text-align: left; -} - -.mb-1 { - margin-bottom: 8px; -} - -.mb-2 { - margin-bottom: 16px; -} - -.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