Removed obsolete js versions of files
This commit is contained in:
parent
584926530c
commit
5d80253168
@ -1,77 +0,0 @@
|
|||||||
// js/canvasManager.js
|
|
||||||
|
|
||||||
import { Circle } from './shapes/Circle';
|
|
||||||
import { Triangle } from './shapes/Triangle';
|
|
||||||
|
|
||||||
export function createOrUpdateShapes(container, shapesArray, patches = []) {
|
|
||||||
if (!container || !(container instanceof SVGElement)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure patches is an array
|
|
||||||
const patchArray = patches?.patches || patches || [];
|
|
||||||
if (!Array.isArray(patchArray)) {
|
|
||||||
console.warn("Expected patches to be an array, got:", typeof patchArray, patchArray);
|
|
||||||
patches = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no patches, do a full redraw
|
|
||||||
if (!patchArray || patchArray.length === 0) {
|
|
||||||
// Clear container
|
|
||||||
while (container.firstChild) {
|
|
||||||
container.removeChild(container.firstChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw all shapes
|
|
||||||
shapesArray.forEach(shapeData => {
|
|
||||||
const shape = createShapeInstance(shapeData);
|
|
||||||
if (shape) {
|
|
||||||
const element = shape.createSVGElement();
|
|
||||||
container.appendChild(element);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process patches
|
|
||||||
patchArray.forEach(patch => {
|
|
||||||
if (patch.path[0] === 'shapes') {
|
|
||||||
if (patch.action === 'put') {
|
|
||||||
const shapeIndex = patch.path[1];
|
|
||||||
const shapeData = shapesArray[shapeIndex];
|
|
||||||
if (!shapeData) return;
|
|
||||||
|
|
||||||
const shape = createShapeInstance(shapeData);
|
|
||||||
if (!shape) return;
|
|
||||||
|
|
||||||
let element = document.getElementById(shapeData.id);
|
|
||||||
if (!element) {
|
|
||||||
// Create new element
|
|
||||||
element = shape.createSVGElement();
|
|
||||||
container.appendChild(element);
|
|
||||||
} else {
|
|
||||||
// Update existing element
|
|
||||||
shape.updateAttributes(element);
|
|
||||||
}
|
|
||||||
} else if (patch.action === 'del') {
|
|
||||||
const element = document.getElementById(patch.path[1]);
|
|
||||||
if (element) {
|
|
||||||
container.removeChild(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function createShapeInstance(shapeData) {
|
|
||||||
switch (shapeData.type) {
|
|
||||||
case "circle":
|
|
||||||
return new Circle(shapeData.id, shapeData.x, shapeData.y, shapeData.radius, shapeData.color);
|
|
||||||
case "triangle":
|
|
||||||
return new Triangle(shapeData.id, shapeData.coordinates, shapeData.color);
|
|
||||||
default:
|
|
||||||
console.warn(`Unknown shape type: ${shapeData.type}`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,130 +0,0 @@
|
|||||||
// docManager.js (Automerge 2.x style)
|
|
||||||
|
|
||||||
import { Repo, isValidAutomergeUrl } from "@automerge/automerge-repo"
|
|
||||||
import * as Automerge from "@automerge/automerge"
|
|
||||||
// For IndexedDB storage
|
|
||||||
import { IndexedDBStorageAdapter } from '@automerge/automerge-repo-storage-indexeddb'
|
|
||||||
import { BrowserWebSocketClientAdapter } from "@automerge/automerge-repo-network-websocket"
|
|
||||||
|
|
||||||
let handle
|
|
||||||
|
|
||||||
// Define the current schema version
|
|
||||||
const CURRENT_SCHEMA_VERSION = 1;
|
|
||||||
|
|
||||||
export async function initRepo() {
|
|
||||||
const repo = new Repo({
|
|
||||||
network: [
|
|
||||||
new BrowserWebSocketClientAdapter("wss://automerge.rheinheim.fraction.ch")
|
|
||||||
],
|
|
||||||
storage: new IndexedDBStorageAdapter()
|
|
||||||
})
|
|
||||||
|
|
||||||
// Check for existing docId in URL hash
|
|
||||||
const rootDocUrl = document.location.hash.substring(1)
|
|
||||||
|
|
||||||
if (rootDocUrl && isValidAutomergeUrl(rootDocUrl)) {
|
|
||||||
handle = repo.find(rootDocUrl)
|
|
||||||
// Wait for handle to be ready
|
|
||||||
await handle.whenReady()
|
|
||||||
|
|
||||||
// Check and upgrade schema if needed
|
|
||||||
handle.change(doc => {
|
|
||||||
if (!doc.schemaVersion) {
|
|
||||||
// Handle legacy documents (pre-versioning)
|
|
||||||
doc.schemaVersion = 1
|
|
||||||
}
|
|
||||||
// Add future upgrade logic here
|
|
||||||
// if (doc.schemaVersion < 2) {
|
|
||||||
// // Example: upgrade shapes to include a new required field
|
|
||||||
// doc.shapes.forEach(shape => {
|
|
||||||
// shape.opacity = 1.0 // Add new field with default value
|
|
||||||
// })
|
|
||||||
// doc.schemaVersion = 2
|
|
||||||
// }
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// Create new document with current schema version
|
|
||||||
handle = repo.create({
|
|
||||||
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
||||||
shapes: []
|
|
||||||
})
|
|
||||||
// Wait for handle to be ready
|
|
||||||
await handle.whenReady()
|
|
||||||
document.location.hash = handle.url
|
|
||||||
}
|
|
||||||
|
|
||||||
return handle
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a new circle to the document
|
|
||||||
*/
|
|
||||||
export function addCircle(x, y, radius) {
|
|
||||||
handle.change(doc => {
|
|
||||||
doc.shapes.push({
|
|
||||||
id: Date.now(),
|
|
||||||
type: "circle",
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
radius,
|
|
||||||
color: "red"
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fügt dem Dokument ein Dreieck hinzu
|
|
||||||
*/
|
|
||||||
export function addTriangle(x1, y1, x2, y2, x3, y3) {
|
|
||||||
handle.change(doc => {
|
|
||||||
doc.shapes.push({
|
|
||||||
id: Date.now(),
|
|
||||||
type: "triangle",
|
|
||||||
coordinates: [
|
|
||||||
{ x: x1, y: y1 },
|
|
||||||
{ x: x2, y: y2 },
|
|
||||||
{ x: x3, y: y3 }
|
|
||||||
],
|
|
||||||
color: "blue"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move a shape in the document
|
|
||||||
*
|
|
||||||
* Watch out: do not use the Array.find method, because these are Proxies and the find method is not supported on Proxies.
|
|
||||||
* Also make sure that you compare numbers with numbers, not strings.
|
|
||||||
*/
|
|
||||||
export function moveShape(shapeId, newX, newY) {
|
|
||||||
handle.change(doc => {
|
|
||||||
// Find the index of the shape instead of using find()
|
|
||||||
// TODO faster implementation than for loop
|
|
||||||
for (let i = 0; i < doc.shapes.length; i++) {
|
|
||||||
if (doc.shapes[i].id === Number(shapeId)) {
|
|
||||||
if (doc.shapes[i].type === "circle") {
|
|
||||||
doc.shapes[i].x = newX;
|
|
||||||
doc.shapes[i].y = newY;
|
|
||||||
} else if (doc.shapes[i].type === "triangle") {
|
|
||||||
// Calculate the current center
|
|
||||||
const center = {
|
|
||||||
x: doc.shapes[i].coordinates.reduce((sum, p) => sum + p.x, 0) / 3,
|
|
||||||
y: doc.shapes[i].coordinates.reduce((sum, p) => sum + p.y, 0) / 3
|
|
||||||
};
|
|
||||||
// Calculate the movement delta
|
|
||||||
const dx = newX - center.x;
|
|
||||||
const dy = newY - center.y;
|
|
||||||
|
|
||||||
// Move all points
|
|
||||||
doc.shapes[i].coordinates = doc.shapes[i].coordinates.map(p => ({
|
|
||||||
x: p.x + dx,
|
|
||||||
y: p.y + dy
|
|
||||||
}));
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
94
src/main.js
94
src/main.js
@ -1,94 +0,0 @@
|
|||||||
// main.js
|
|
||||||
import { initRepo, addCircle, addTriangle, moveShape } from "./docManager.js"
|
|
||||||
import { createOrUpdateShapes } from "./canvasManager.js"
|
|
||||||
|
|
||||||
const CONFIG = {
|
|
||||||
THROTTLE_MS: 16, // 60fps
|
|
||||||
DEFAULT_SHAPES: {
|
|
||||||
CIRCLE: { x: 100, y: 100, radius: 30 },
|
|
||||||
TRIANGLE: { x1: 200, y1: 200, x2: 220, y2: 220, x3: 180, y3: 220 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Group related event handlers together
|
|
||||||
function initDragAndDrop(container) {
|
|
||||||
let isDragging = false;
|
|
||||||
let selectedShapeId = null;
|
|
||||||
|
|
||||||
const throttledMoveShape = throttle((shapeId, x, y) => {
|
|
||||||
moveShape(shapeId, x, y);
|
|
||||||
}, CONFIG.THROTTLE_MS);
|
|
||||||
|
|
||||||
container.addEventListener("mousedown", (e) => {
|
|
||||||
const clickedElement = e.target;
|
|
||||||
if (clickedElement.matches('circle, polygon')) {
|
|
||||||
isDragging = true;
|
|
||||||
selectedShapeId = clickedElement.id;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
container.addEventListener("mousemove", (e) => {
|
|
||||||
if (!isDragging || !selectedShapeId) return;
|
|
||||||
|
|
||||||
const svgPoint = getSVGPoint(container, e.clientX, e.clientY);
|
|
||||||
throttledMoveShape(selectedShapeId, svgPoint.x, svgPoint.y);
|
|
||||||
});
|
|
||||||
|
|
||||||
container.addEventListener("mouseup", () => {
|
|
||||||
isDragging = false;
|
|
||||||
selectedShapeId = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function for SVG coordinate conversion
|
|
||||||
function getSVGPoint(container, x, y) {
|
|
||||||
const pt = container.createSVGPoint();
|
|
||||||
pt.x = x;
|
|
||||||
pt.y = y;
|
|
||||||
return pt.matrixTransform(container.getScreenCTM().inverse());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add throttle function at the top
|
|
||||||
function throttle(func, limit) {
|
|
||||||
let inThrottle;
|
|
||||||
return function(...args) {
|
|
||||||
if (!inThrottle) {
|
|
||||||
func.apply(this, args);
|
|
||||||
inThrottle = true;
|
|
||||||
setTimeout(() => inThrottle = false, limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function initApp() {
|
|
||||||
const container = document.getElementById("shapesCanvas");
|
|
||||||
const handle = await initRepo();
|
|
||||||
|
|
||||||
// Initial render
|
|
||||||
createOrUpdateShapes(container, handle.docSync().shapes);
|
|
||||||
|
|
||||||
// Subscribe to changes
|
|
||||||
handle.on("change", (change) => {
|
|
||||||
createOrUpdateShapes(container, change.doc.shapes, change.patches);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize shape buttons
|
|
||||||
initShapeButtons();
|
|
||||||
initDragAndDrop(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
function initShapeButtons() {
|
|
||||||
document.getElementById("addCircleButton").addEventListener("click", () => {
|
|
||||||
const { x, y, radius } = CONFIG.DEFAULT_SHAPES.CIRCLE;
|
|
||||||
addCircle(x, y, radius);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById("addTriangleButton").addEventListener("click", () => {
|
|
||||||
const { x1, y1, x2, y2, x3, y3 } = CONFIG.DEFAULT_SHAPES.TRIANGLE;
|
|
||||||
addTriangle(x1, y1, x2, y2, x3, y3);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the app
|
|
||||||
initApp().catch(console.error);
|
|
||||||
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
import { Shape } from './Shape';
|
|
||||||
|
|
||||||
export class Circle extends Shape {
|
|
||||||
constructor(id, x, y, radius, color = "red") {
|
|
||||||
super(id, "circle", color);
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.radius = radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSVGElementType() {
|
|
||||||
return "circle";
|
|
||||||
}
|
|
||||||
|
|
||||||
updateAttributes(element) {
|
|
||||||
element.setAttributeNS(null, "cx", this.x);
|
|
||||||
element.setAttributeNS(null, "cy", this.y);
|
|
||||||
element.setAttributeNS(null, "r", this.radius);
|
|
||||||
element.setAttributeNS(null, "fill", this.color);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
||||||
|
|
||||||
export class Shape {
|
|
||||||
constructor(id, type, color = "black") {
|
|
||||||
this.id = id;
|
|
||||||
this.type = type;
|
|
||||||
this.color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
createSVGElement() {
|
|
||||||
const element = document.createElementNS(SVG_NS, this.getSVGElementType());
|
|
||||||
element.id = this.id;
|
|
||||||
this.updateAttributes(element);
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Abstract methods
|
|
||||||
getSVGElementType() {
|
|
||||||
throw new Error("Must be implemented by derived class");
|
|
||||||
}
|
|
||||||
// this update also takes care of movements. The actual movement is done in documentManager.js
|
|
||||||
updateAttributes(element) {
|
|
||||||
throw new Error("Must be implemented by derived class");
|
|
||||||
}
|
|
||||||
|
|
||||||
move(newX, newY) {
|
|
||||||
throw new Error("Must be implemented by derived class");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
import { Shape } from './Shape';
|
|
||||||
|
|
||||||
export class Triangle extends Shape {
|
|
||||||
constructor(id, coordinates, color = "blue") {
|
|
||||||
super(id, "triangle", color);
|
|
||||||
this.coordinates = coordinates;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSVGElementType() {
|
|
||||||
return "polygon";
|
|
||||||
}
|
|
||||||
|
|
||||||
updateAttributes(element) {
|
|
||||||
const points = this.coordinates
|
|
||||||
.map(p => `${p.x},${p.y}`)
|
|
||||||
.join(" ");
|
|
||||||
element.setAttributeNS(null, "points", points);
|
|
||||||
element.setAttributeNS(null, "fill", this.color);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user