feat(ui): implement polygon tool

This commit is contained in:
max_richter 2021-03-16 13:31:55 +01:00
parent 0e461edd38
commit b96f820971
9 changed files with 1549 additions and 4993 deletions

3597
view/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -35,10 +35,12 @@
},
"dependencies": {
"@tensorflow-models/deeplab": "^0.2.1",
"@tensorflow/tfjs-backend-cpu": "^3.3.0",
"@tensorflow/tfjs-backend-webgl": "^3.3.0",
"@tensorflow/tfjs-converter": "^3.3.0",
"@tensorflow/tfjs-core": "^3.3.0",
"file-selector": "^0.2.4",
"lodash": "^4.17.21",
"ogl": "^0.0.65"
}
}

1411
view/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -6,8 +6,18 @@
export let image: Image;
let activeTool = "brush";
const _activeTool = localStorage.getItem("activeTool");
if (_activeTool) {
activeTool = _activeTool;
}
let brushRadius = 20;
let activeColor = "ff0000";
let _activeColor = localStorage.getItem("activeColor");
if (_activeColor) {
activeColor = _activeColor;
}
let layerOpacity = 50;
</script>
@ -26,7 +36,12 @@
<ToolBox bind:activeTool />
</div>
<div class="top">
<TopBar bind:layerOpacity bind:brushRadius bind:activeColor />
<TopBar
bind:layerOpacity
bind:brushRadius
bind:activeColor
bind:activeTool
/>
</div>
<div class="back">
<button on:click={() => ($currentRoute = "list")}>exit</button>

View File

@ -4,6 +4,7 @@
import OrbView from "./OrbView";
import { onMount } from "svelte";
import Toast from "components/Toast";
import { throttle } from "lodash";
export let image: Image;
export let activeTool = "pan";
@ -21,16 +22,27 @@
let cx2: CanvasRenderingContext2D;
let orb: ReturnType<typeof OrbView>;
$: if (activeTool) {
let _lastActiveTool;
function handleToolChange(t) {
if (_lastActiveTool === t) return;
if (orb) {
orb.setTool(activeTool);
orb.setTool(t);
}
if (activeTool === "clear") {
if (t === "clear") {
cx1.clearRect(0, 0, image.width, image.height);
cx2.clearRect(0, 0, image.width, image.height);
saveToImage();
activeTool = "brush";
}
if (_lastActiveTool === "polygon") {
handleFinishPolygon();
}
_lastActiveTool = t;
}
$: if (activeTool) {
handleToolChange(activeTool);
}
$: if (layerOpacity && orb) orb.setOpacity(layerOpacity);
@ -59,8 +71,6 @@
let debugValue = 0;
let debugY = 0;
let isStrPressed = false;
let isSpacePressed = false;
let lastActiveTool;
function scaleImageData(imageData, scale) {
@ -117,7 +127,7 @@
let prePolygonImage = new Image(image.width, image.height);
let lastPolyX;
let lastPolyY;
function drawPolygon() {
function drawSmoothPolygon() {
const x = Math.floor(
mx * wrapperHeightRatio - xOffset * wrapperHeightRatio
);
@ -150,7 +160,53 @@
prePolygonImage.src = canvas.toDataURL();
}
function switchMode(e: MouseEvent) {
function handlePolygonMouseDown() {
if (polygonPoints.length < 2) savePrePolygon();
const x = Math.floor(
mx * wrapperHeightRatio - xOffset * wrapperHeightRatio
);
const y = Math.floor(my * wrapperHeightRatio);
polygonPoints.push(x, y);
drawPolygon();
}
function handleFinishPolygon() {
// console.trace("BAD");
drawPolygon(false);
if (polygonPoints.length) {
polygonPoints = [];
lastPolyX = undefined;
lastPolyY = undefined;
}
}
function drawPolygon(showMouse = true) {
if (polygonPoints.length < 2) return;
cx1.clearRect(0, 0, image.width, image.height);
cx1.drawImage(prePolygonImage, 0, 0, image.width, image.height);
cx1.beginPath();
cx1.moveTo(polygonPoints[0], polygonPoints[1]);
for (let i = 2; i < polygonPoints.length; i += 2) {
cx1.lineTo(polygonPoints[i], polygonPoints[i + 1]);
}
if (showMouse) {
const x = Math.floor(
mx * wrapperHeightRatio - xOffset * wrapperHeightRatio
);
const y = Math.floor(my * wrapperHeightRatio);
cx1.lineTo(x, y);
}
cx1.fillStyle = cx1.strokeStyle = "#" + activeColor;
cx1.closePath();
cx1.lineWidth = 1;
polygonPoints.length === 2 ? cx1.stroke() : cx1.fill();
}
function switchViewMode(e: MouseEvent) {
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
@ -163,9 +219,17 @@
}
mode === "2d" ? orb.stop() : orb.start();
handleFinishPolygon();
}
let lastMouseDown;
function handleMouseDown(e: MouseEvent) {
// Double Click detection
if (!lastMouseDown) lastMouseDown = 0;
let t = Date.now();
let isDbClick = t - lastMouseDown < 200;
lastMouseDown = t;
if (e.button === 1) {
lastActiveTool = activeTool;
activeTool = "pan";
@ -178,6 +242,13 @@
if (activeTool === "smooth_polygon") {
savePrePolygon();
}
if (activeTool === "polygon") {
if (isDbClick) {
handleFinishPolygon();
} else {
handlePolygonMouseDown();
}
}
}
function handleMouseUp(e) {
@ -190,27 +261,12 @@
saveToImage();
}
function handleMouseMove(e) {
const handleMouseMove = throttle((e) => {
mx = Math.floor(e.clientX - topLeftX);
my = Math.floor(e.clientY - topLeftY);
isOriginal = e.target.id === "cx1";
//Caclulate y position of pixel
const y = Math.floor(my * wrapperHeightRatio);
debugY = y;
const height = image.height;
// KarlKilian Formel
//debugValue = (2 * Math.sqrt(y * (image.height - y))) / image.height;
// New new formel
debugValue = Math.cos(
(((360 / height ** 2) * y ** 2 + (-360 / height) * y + 90) / 360) *
2 *
Math.PI
);
if (isDown) {
if (activeTool === "pan") {
// TODO fix overflowiung
@ -237,19 +293,22 @@
cx1.globalCompositeOperation = "source-over";
}
if (activeTool === "smooth_polygon") drawPolygon();
if (activeTool === "smooth_polygon") drawSmoothPolygon();
if (activeTool === "brush") drawBrush();
}
if (activeTool === "polygon") {
drawPolygon(true);
}
}, 50);
function handleKeyDown(e) {
if (e.keyCode === 69) activeTool = "erasor";
if (e.keyCode === 66) activeTool = "brush";
if (e.keyCode === 17) isStrPressed = true;
if (e.key === "Enter") handleFinishPolygon();
//SPACE
if (e.keyCode === 32) {
isSpacePressed = true;
if (!lastActiveTool) {
lastActiveTool = activeTool;
activeTool = "pan";
@ -258,7 +317,6 @@
}
function handleKeyUp(e) {
if (e.keyCode === 17) isStrPressed = false;
//SPACE
if (e.keyCode === 32) {
activeTool = lastActiveTool;
@ -347,7 +405,7 @@
class:is-down={isDown}
style={`background-image: url(${imageUrl}); background-position: ${xOffset}px ${0}px`}
>
<button id="mode" on:click={switchMode}>
<button id="mode" on:click={switchViewMode}>
{mode}
</button>
@ -360,7 +418,9 @@
id="cursor"
style={`width: ${brushRadius * 2}px; height: ${
brushRadius * 2
}px; background-color: #${activeColor}; top: ${my}px; left: ${mx}px`}
}px; background-color: #${activeColor}; transform: translate(${
mx - brushRadius
}px, ${my - brushRadius}px);`}
/>
{/if}
@ -382,19 +442,10 @@
}%)); opacity: ${(layerOpacity / 100) * 0.5};`}
/>
<p>h:{image.height} | y:{debugY} | value:{debugValue}</p>
<canvas class:visible={mode === "3d"} bind:this={canvas3D} />
</div>
<style>
p {
position: absolute;
top: 0px;
left: 0px;
z-index: 1001;
}
#ai {
position: absolute;
top: 60px;
@ -424,7 +475,6 @@
opacity: 0.5;
z-index: 99;
border-radius: 100%;
transform: translateX(-50%) translateY(-50%);
}
.wrapper.tool-pan {

View File

@ -6,7 +6,12 @@
export let activeTool = "pan";
const tools = ["pan", "brush", "erasor", "smooth_polygon"];
const tools = ["pan", "brush", "erasor", "smooth_polygon", "polygon"];
$: if (activeTool) {
if (!tools.includes(activeTool)) activeTool = "brush";
localStorage.setItem("activeTool", activeTool);
}
</script>
{#each tools as t}

View File

@ -1,5 +1,6 @@
<script>
export let activeColor = "ff0000";
export let activeTool;
const minRadius = 1;
const maxRadius = 100;
@ -8,6 +9,11 @@
const colors = ["ff0000", "00ff00", "0000ff", "ffff00", "00ffff", "ff00ff"];
$: if (activeColor) {
if (!colors.includes(activeColor)) activeColor = colors[0];
localStorage.setItem("activeColor", activeColor);
}
function handleMouseWheel(e) {
brushRadius = Math.min(
Math.max(brushRadius - e.deltaY / 10, minRadius),
@ -31,6 +37,7 @@
</div>
<div class="settings-wrapper">
{#if activeTool === "brush" || activeTool === "erasor"}
<label for="brush-radius">Brush Radius</label>
<input
id="brush-radius"
@ -39,6 +46,7 @@
max={maxRadius}
bind:value={brushRadius}
/>
{/if}
<!-- <label for="brush-radius">LayerOpacity</label>
<input
id="brush-radius"

File diff suppressed because it is too large Load Diff

8
yarn.lock Normal file
View File

@ -0,0 +1,8 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==