add ellipse tool

This commit is contained in:
Skyler Lehmkuhl 2024-12-05 10:35:49 -05:00
parent 7d3f414be9
commit 88d95d7c3a
4 changed files with 156 additions and 34 deletions

View File

@ -10,7 +10,10 @@
"@tauri-apps/cli": "^2"
},
"dependencies": {
"@ffmpeg/ffmpeg": "^0.12.10",
"@tauri-apps/plugin-dialog": "~2",
"@tauri-apps/plugin-fs": "~2"
"@tauri-apps/plugin-fs": "~2",
"ffmpeg": "^0.0.4",
"ffmpeg.js": "^4.2.9003"
}
}

View File

@ -8,12 +8,21 @@ importers:
.:
dependencies:
'@ffmpeg/ffmpeg':
specifier: ^0.12.10
version: 0.12.10
'@tauri-apps/plugin-dialog':
specifier: ~2
version: 2.0.1
'@tauri-apps/plugin-fs':
specifier: ~2
version: 2.0.2
ffmpeg:
specifier: ^0.0.4
version: 0.0.4
ffmpeg.js:
specifier: ^4.2.9003
version: 4.2.9003
devDependencies:
'@tauri-apps/cli':
specifier: ^2
@ -21,6 +30,14 @@ importers:
packages:
'@ffmpeg/ffmpeg@0.12.10':
resolution: {integrity: sha512-lVtk8PW8e+NUzGZhPTWj2P1J4/NyuCrbDD3O9IGpSeLYtUZKBqZO8CNj1WYGghep/MXoM8e1qVY1GztTkf8YYQ==}
engines: {node: '>=18.x'}
'@ffmpeg/types@0.12.2':
resolution: {integrity: sha512-NJtxwPoLb60/z1Klv0ueshguWQ/7mNm106qdHkB4HL49LXszjhjCCiL+ldHJGQ9ai2Igx0s4F24ghigy//ERdA==}
engines: {node: '>=16.x'}
'@tauri-apps/api@2.1.1':
resolution: {integrity: sha512-fzUfFFKo4lknXGJq8qrCidkUcKcH2UHhfaaCNt4GzgzGaW2iS26uFOg4tS3H4P8D6ZEeUxtiD5z0nwFF0UN30A==}
@ -95,8 +112,23 @@ packages:
'@tauri-apps/plugin-fs@2.0.2':
resolution: {integrity: sha512-4YZaX2j7ta81M5/DL8aN10kTnpUkEpkPo1FTYPT8Dd0ImHe3azM8i8MrtjrDGoyBYLPO3zFv7df/mSCYF8oA0Q==}
ffmpeg.js@4.2.9003:
resolution: {integrity: sha512-l1JBr8HwnnJEaSwg5p8K3Ifbom8O2IDHsZp7UVyr6MzQ7gc32tt/2apoOuQAr/j76c+uDOjla799VSsBnRvSTg==}
ffmpeg@0.0.4:
resolution: {integrity: sha512-3TgWUJJlZGQn+crJFyhsO/oNeRRnGTy6GhgS98oUCIfZrOW5haPPV7DUfOm3xJcHr5q3TJpjk2GudPutrNisRA==}
when@3.7.8:
resolution: {integrity: sha512-5cZ7mecD3eYcMiCH4wtRPA5iFJZ50BJYDfckI5RRpQiktMiYTcn0ccLTZOvcbBume+1304fQztxeNzNS9Gvrnw==}
snapshots:
'@ffmpeg/ffmpeg@0.12.10':
dependencies:
'@ffmpeg/types': 0.12.2
'@ffmpeg/types@0.12.2': {}
'@tauri-apps/api@2.1.1': {}
'@tauri-apps/cli-darwin-arm64@2.0.4':
@ -149,3 +181,11 @@ snapshots:
'@tauri-apps/plugin-fs@2.0.2':
dependencies:
'@tauri-apps/api': 2.1.1
ffmpeg.js@4.2.9003: {}
ffmpeg@0.0.4:
dependencies:
when: 3.7.8
when@3.7.8: {}

View File

@ -3,7 +3,7 @@ import * as fitCurve from '/fit-curve.js';
import { Bezier } from "/bezier.js";
import { Quadtree } from './quadtree.js';
import { createNewFileDialog, showNewFileDialog, closeDialog } from './newfile.js';
import { titleCase, getMousePositionFraction, getKeyframesSurrounding, invertPixels } from './utils.js';
import { titleCase, getMousePositionFraction, getKeyframesSurrounding, invertPixels, lerpColor, lerp } from './utils.js';
const { writeTextFile: writeTextFile, readTextFile: readTextFile, writeFile: writeFile }= window.__TAURI__.fs;
const {
open: openFileDialog,
@ -276,6 +276,7 @@ let actions = {
});
}
img = await loadImage(action.src)
console.log(img.crossOrigin)
// img.onload = function() {
let ct = {
...context,
@ -959,6 +960,7 @@ class BaseShape {
ctx.fill()
}
if (this.stroked) {
console.log(this.curves)
for (let curve of this.curves) {
ctx.strokeStyle = curve.color
ctx.beginPath()
@ -968,9 +970,11 @@ class BaseShape {
curve.points[3].x, curve.points[3].y)
ctx.stroke()
// Debug, show curve endpoints
// // Debug, show curve control points
// ctx.beginPath()
// ctx.arc(curve.points[3].x,curve.points[3].y, 3, 0, 2*Math.PI)
// ctx.arc(curve.points[1].x,curve.points[1].y, 5, 0, 2*Math.PI)
// ctx.arc(curve.points[2].x,curve.points[2].y, 5, 0, 2*Math.PI)
// ctx.arc(curve.points[3].x,curve.points[3].y, 5, 0, 2*Math.PI)
// ctx.fill()
}
}
@ -981,12 +985,14 @@ class BaseShape {
}
class TempShape extends BaseShape {
constructor(startx, starty, curves, lineWidth, stroked, filled) {
constructor(startx, starty, curves, lineWidth, stroked, filled, strokeStyle, fillStyle) {
super(startx, starty)
this.curves = curves
this.lineWidth = lineWidth
this.stroked = stroked
this.filled = filled
this.strokeStyle = strokeStyle
this.fillStyle = fillStyle
this.inProgress = false
}
}
@ -1380,8 +1386,6 @@ class GraphicsObject {
})
}
}
console.log(path1)
console.log(path2)
const interpolator = d3.interpolatePathCommands(path1, path2)
let current = interpolator(t)
let curves = []
@ -1392,9 +1396,16 @@ class GraphicsObject {
x = curve.x
y = curve.y
}
console.log(curves)
// TODO: lerp lineWidth
shapes.push(new TempShape(start.x, start.y, curves, shape1.lineWidth, shape1.stroked))
let lineWidth = lerp(shape1.lineWidth, shape2.lineWidth, t)
let strokeStyle = lerpColor(shape1.strokeStyle, shape2.strokeStyle, t)
let fillStyle;
if (!shape1.fillImage) {
fillStyle = lerpColor(shape1.fillStyle, shape2.fillStyle, t)
}
shapes.push(new TempShape(
start.x, start.y, curves, shape1.lineWidth,
shape1.stroked, shape1.filled, strokeStyle, fillStyle
))
}
}
let frame = new Frame("shape", "temp")
@ -1899,7 +1910,7 @@ async function render() {
exportContext.ctx.fillStyle = "white"
exportContext.ctx.rect(0,0,fileWidth, fileHeight)
exportContext.ctx.fill()
root.draw(exportContext)
await root.draw(exportContext)
// Convert the canvas content to a PNG image (this is the "frame" we add to the APNG)
const imageData = exportContext.ctx.getImageData(0, 0, canvas.width, canvas.height);
@ -1983,7 +1994,7 @@ function stage() {
e.preventDefault()
let mouse = getMousePos(stage, e)
const imageTypes = ['image/png', 'image/gif', 'image/avif', 'image/jpeg',
'image/svg+xml', 'image/webp'
'image/webp', //'image/svg+xml' // Disabling SVG until we can export them nicely
];
if (e.dataTransfer.items) {
let i = 0
@ -2029,6 +2040,7 @@ function stage() {
let mouse = getMousePos(stage, e)
switch (mode) {
case "rectangle":
case "ellipse":
case "draw":
context.mouseDown = true
context.activeShape = new Shape(mouse.x, mouse.y, context, true, true)
@ -2141,6 +2153,7 @@ function stage() {
}
break;
case "rectangle":
case "ellipse":
actions.addShape.create(context.activeObject, context.activeShape)
context.activeShape = undefined
break;
@ -2205,6 +2218,41 @@ function stage() {
context.activeShape.update()
}
break;
case "ellipse":
context.activeCurve = undefined
if (context.activeShape) {
let midX = (mouse.x + context.activeShape.startx) / 2
let midY = (mouse.y + context.activeShape.starty) / 2
let xDiff = (mouse.x - context.activeShape.startx) / 2
let yDiff = (mouse.y - context.activeShape.starty) / 2
let ellipseConst = 0.552284749831
context.activeShape.clear()
context.activeShape.addCurve(new Bezier(
midX, context.activeShape.starty,
midX + ellipseConst * xDiff, context.activeShape.starty,
mouse.x, midY - ellipseConst * yDiff,
mouse.x, midY
))
context.activeShape.addCurve(new Bezier(
mouse.x, midY,
mouse.x, midY + ellipseConst * yDiff,
midX + ellipseConst * xDiff, mouse.y,
midX, mouse.y
))
context.activeShape.addCurve(new Bezier(
midX, mouse.y,
midX - ellipseConst * xDiff, mouse.y,
context.activeShape.startx, midY + ellipseConst * yDiff,
context.activeShape.startx, midY
))
context.activeShape.addCurve(new Bezier(
context.activeShape.startx, midY,
context.activeShape.startx, midY - ellipseConst * yDiff,
midX - ellipseConst * xDiff, context.activeShape.starty,
midX, context.activeShape.starty
))
break;
}
case "select":
if (context.dragging) {
if (context.activeVertex) {

View File

@ -91,4 +91,35 @@ function invertPixels(ctx, width, height) {
ctx.globalCompositeOperation = "source-over"
}
export { titleCase, getMousePositionFraction, getKeyframesSurrounding, invertPixels };
function lerp(a, b, t) {
return a + (b - a) * t;
}
function lerpColor(color1, color2, t) {
// Convert hex color to RGB
const hexToRgb = (hex) => {
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return { r, g, b };
};
// Convert RGB to hex color
const rgbToHex = (r, g, b) => {
return `#${(1 << 24 | (r << 16) | (g << 8) | b).toString(16).slice(1).toUpperCase()}`;
};
// Get RGB values of both colors
const start = hexToRgb(color1);
const end = hexToRgb(color2);
// Calculate the interpolated RGB values
const r = Math.round(start.r + (end.r - start.r) * t);
const g = Math.round(start.g + (end.g - start.g) * t);
const b = Math.round(start.b + (end.b - start.b) * t);
// Convert the interpolated RGB back to hex
return rgbToHex(r, g, b);
}
export { titleCase, getMousePositionFraction, getKeyframesSurrounding, invertPixels, lerp, lerpColor };