Add SeatingTemplateTool for predefined seating layouts
This commit is contained in:
@@ -0,0 +1,339 @@
|
|||||||
|
import { Tool } from '../Tool';
|
||||||
|
import { YjsDocument } from '../../crdt/YjsDocument';
|
||||||
|
|
||||||
|
type SeatingTemplate = 'bankett' | 'gala' | 'stehempfang' | 'parlament' | 'klasse';
|
||||||
|
|
||||||
|
class SeatingTemplateTool extends Tool {
|
||||||
|
private template: SeatingTemplate = 'bankett';
|
||||||
|
private tableSpacing: number = 150; // Spacing between tables
|
||||||
|
private chairSpacing: number = 60; // Spacing between chairs
|
||||||
|
|
||||||
|
constructor(yjsDoc: YjsDocument, template: SeatingTemplate = 'bankett') {
|
||||||
|
super(yjsDoc);
|
||||||
|
this.name = 'SeatingTemplateTool';
|
||||||
|
this.template = template;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseDown(event: MouseEvent): void {
|
||||||
|
// This tool creates templates at the click position
|
||||||
|
const x = event.clientX;
|
||||||
|
const y = event.clientY;
|
||||||
|
|
||||||
|
switch (this.template) {
|
||||||
|
case 'bankett':
|
||||||
|
this.createBankettTemplate(x, y);
|
||||||
|
break;
|
||||||
|
case 'gala':
|
||||||
|
this.createGalaTemplate(x, y);
|
||||||
|
break;
|
||||||
|
case 'stehempfang':
|
||||||
|
this.createStehempfangTemplate(x, y);
|
||||||
|
break;
|
||||||
|
case 'parlament':
|
||||||
|
this.createParlamentTemplate(x, y);
|
||||||
|
break;
|
||||||
|
case 'klasse':
|
||||||
|
this.createKlasseTemplate(x, y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseMove(event: MouseEvent): void {
|
||||||
|
// Preview template at cursor position
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseUp(event: MouseEvent): void {
|
||||||
|
// Handle mouse up if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyUp(event: KeyboardEvent): void {
|
||||||
|
// Handle key up events
|
||||||
|
if (event.key === 'Escape') {
|
||||||
|
this.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reset(): void {
|
||||||
|
// Reset any state if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Bankett template (long tables with chairs on both sides)
|
||||||
|
private createBankettTemplate(x: number, y: number): void {
|
||||||
|
const tableWidth = 240;
|
||||||
|
const tableHeight = 100;
|
||||||
|
const chairWidth = 45;
|
||||||
|
const chairHeight = 45;
|
||||||
|
const tablesCount = 3;
|
||||||
|
|
||||||
|
for (let i = 0; i < tablesCount; i++) {
|
||||||
|
const tableX = x + i * (tableWidth + this.tableSpacing);
|
||||||
|
const tableY = y;
|
||||||
|
|
||||||
|
// Create table
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_table_' + i,
|
||||||
|
type: 'rectangular_table',
|
||||||
|
layerId: 'default',
|
||||||
|
x: tableX,
|
||||||
|
y: tableY,
|
||||||
|
width: tableWidth,
|
||||||
|
height: tableHeight,
|
||||||
|
properties: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create chairs on both sides
|
||||||
|
const chairsPerSide = 4;
|
||||||
|
for (let j = 0; j < chairsPerSide; j++) {
|
||||||
|
const positionRatio = (j + 1) / (chairsPerSide + 1);
|
||||||
|
|
||||||
|
// Top side chairs
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_chair_top_' + i + '_' + j,
|
||||||
|
type: 'chair',
|
||||||
|
layerId: 'default',
|
||||||
|
x: tableX + positionRatio * tableWidth - chairWidth / 2,
|
||||||
|
y: tableY - this.chairSpacing - chairHeight,
|
||||||
|
width: chairWidth,
|
||||||
|
height: chairHeight,
|
||||||
|
properties: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bottom side chairs
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_chair_bottom_' + i + '_' + j,
|
||||||
|
type: 'chair',
|
||||||
|
layerId: 'default',
|
||||||
|
x: tableX + positionRatio * tableWidth - chairWidth / 2,
|
||||||
|
y: tableY + tableHeight + this.chairSpacing,
|
||||||
|
width: chairWidth,
|
||||||
|
height: chairHeight,
|
||||||
|
properties: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Gala template (round tables with chairs around)
|
||||||
|
private createGalaTemplate(x: number, y: number): void {
|
||||||
|
const tableRadius = 50;
|
||||||
|
const tablesPerRow = 3;
|
||||||
|
const tablesRows = 2;
|
||||||
|
|
||||||
|
for (let i = 0; i < tablesRows; i++) {
|
||||||
|
for (let j = 0; j < tablesPerRow; j++) {
|
||||||
|
const tableX = x + j * (tableRadius * 2 + this.tableSpacing);
|
||||||
|
const tableY = y + i * (tableRadius * 2 + this.tableSpacing);
|
||||||
|
|
||||||
|
// Create round table
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_table_' + i + '_' + j,
|
||||||
|
type: 'round_table',
|
||||||
|
layerId: 'default',
|
||||||
|
x: tableX - tableRadius,
|
||||||
|
y: tableY - tableRadius,
|
||||||
|
width: tableRadius * 2,
|
||||||
|
height: tableRadius * 2,
|
||||||
|
properties: {
|
||||||
|
radius: tableRadius,
|
||||||
|
centerX: tableX,
|
||||||
|
centerY: tableY
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create chairs around table
|
||||||
|
const chairsAround = 8;
|
||||||
|
for (let k = 0; k < chairsAround; k++) {
|
||||||
|
const angle = (2 * Math.PI * k) / chairsAround;
|
||||||
|
const chairX = tableX + (tableRadius + this.chairSpacing) * Math.cos(angle) - 22.5;
|
||||||
|
const chairY = tableY + (tableRadius + this.chairSpacing) * Math.sin(angle) - 22.5;
|
||||||
|
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_chair_' + i + '_' + j + '_' + k,
|
||||||
|
type: 'chair',
|
||||||
|
layerId: 'default',
|
||||||
|
x: chairX,
|
||||||
|
y: chairY,
|
||||||
|
width: 45,
|
||||||
|
height: 45,
|
||||||
|
properties: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Stehempfang template (no chairs, just tables for drinks/food)
|
||||||
|
private createStehempfangTemplate(x: number, y: number): void {
|
||||||
|
const tableWidth = 120;
|
||||||
|
const tableHeight = 60;
|
||||||
|
const tablesPerRow = 4;
|
||||||
|
const tablesRows = 2;
|
||||||
|
|
||||||
|
for (let i = 0; i < tablesRows; i++) {
|
||||||
|
for (let j = 0; j < tablesPerRow; j++) {
|
||||||
|
const tableX = x + j * (tableWidth + this.tableSpacing);
|
||||||
|
const tableY = y + i * (tableHeight + this.tableSpacing);
|
||||||
|
|
||||||
|
// Create table
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_table_' + i + '_' + j,
|
||||||
|
type: 'rectangular_table',
|
||||||
|
layerId: 'default',
|
||||||
|
x: tableX,
|
||||||
|
y: tableY,
|
||||||
|
width: tableWidth,
|
||||||
|
height: tableHeight,
|
||||||
|
properties: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Parlament template (U-shape with chairs)
|
||||||
|
private createParlamentTemplate(x: number, y: number): void {
|
||||||
|
const tableWidth = 200;
|
||||||
|
const tableHeight = 60;
|
||||||
|
const chairWidth = 45;
|
||||||
|
const chairHeight = 45;
|
||||||
|
|
||||||
|
// Create main table (president's table)
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_main_table',
|
||||||
|
type: 'rectangular_table',
|
||||||
|
layerId: 'default',
|
||||||
|
x: x + tableWidth / 2,
|
||||||
|
y: y,
|
||||||
|
width: tableWidth,
|
||||||
|
height: tableHeight,
|
||||||
|
properties: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create side tables (delegates' tables)
|
||||||
|
const sideTablesCount = 4;
|
||||||
|
for (let i = 0; i < sideTablesCount; i++) {
|
||||||
|
// Left side table
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_left_table_' + i,
|
||||||
|
type: 'rectangular_table',
|
||||||
|
layerId: 'default',
|
||||||
|
x: x,
|
||||||
|
y: y + (i + 1) * (tableHeight + this.tableSpacing),
|
||||||
|
width: tableWidth / 2,
|
||||||
|
height: tableHeight,
|
||||||
|
properties: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Right side table
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_right_table_' + i,
|
||||||
|
type: 'rectangular_table',
|
||||||
|
layerId: 'default',
|
||||||
|
x: x + tableWidth + tableWidth / 2,
|
||||||
|
y: y + (i + 1) * (tableHeight + this.tableSpacing),
|
||||||
|
width: tableWidth / 2,
|
||||||
|
height: tableHeight,
|
||||||
|
properties: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create chairs for side tables
|
||||||
|
// Left side chairs
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_left_chair_' + i,
|
||||||
|
type: 'chair',
|
||||||
|
layerId: 'default',
|
||||||
|
x: x - this.chairSpacing - chairWidth,
|
||||||
|
y: y + (i + 1) * (tableHeight + this.tableSpacing) + tableHeight / 2 - chairHeight / 2,
|
||||||
|
width: chairWidth,
|
||||||
|
height: chairHeight,
|
||||||
|
properties: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Right side chairs
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_right_chair_' + i,
|
||||||
|
type: 'chair',
|
||||||
|
layerId: 'default',
|
||||||
|
x: x + tableWidth + tableWidth / 2 + tableWidth / 2 + this.chairSpacing,
|
||||||
|
y: y + (i + 1) * (tableHeight + this.tableSpacing) + tableHeight / 2 - chairHeight / 2,
|
||||||
|
width: chairWidth,
|
||||||
|
height: chairHeight,
|
||||||
|
properties: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Klasse template (U-shape classroom layout)
|
||||||
|
private createKlasseTemplate(x: number, y: number): void {
|
||||||
|
const tableWidth = 120;
|
||||||
|
const tableHeight = 60;
|
||||||
|
const chairWidth = 45;
|
||||||
|
const chairHeight = 45;
|
||||||
|
|
||||||
|
// Create teacher's table
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_teacher_table',
|
||||||
|
type: 'rectangular_table',
|
||||||
|
layerId: 'default',
|
||||||
|
x: x + tableWidth,
|
||||||
|
y: y,
|
||||||
|
width: tableWidth,
|
||||||
|
height: tableHeight,
|
||||||
|
properties: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create student tables in U-shape
|
||||||
|
const rows = 4;
|
||||||
|
const cols = 5;
|
||||||
|
|
||||||
|
for (let i = 0; i < rows; i++) {
|
||||||
|
for (let j = 0; j < cols; j++) {
|
||||||
|
// Skip center tables to create U-shape
|
||||||
|
if (i > 0 && i < rows - 1 && j > 0 && j < cols - 1) continue;
|
||||||
|
|
||||||
|
const tableX = x + j * (tableWidth + this.tableSpacing);
|
||||||
|
const tableY = y + (i + 1) * (tableHeight + this.tableSpacing);
|
||||||
|
|
||||||
|
// Create table
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_student_table_' + i + '_' + j,
|
||||||
|
type: 'rectangular_table',
|
||||||
|
layerId: 'default',
|
||||||
|
x: tableX,
|
||||||
|
y: tableY,
|
||||||
|
width: tableWidth,
|
||||||
|
height: tableHeight,
|
||||||
|
properties: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create chair behind each table
|
||||||
|
this.yjsDoc.createElement({
|
||||||
|
id: Date.now().toString() + '_student_chair_' + i + '_' + j,
|
||||||
|
type: 'chair',
|
||||||
|
layerId: 'default',
|
||||||
|
x: tableX + tableWidth / 2 - chairWidth / 2,
|
||||||
|
y: tableY + tableHeight + this.chairSpacing,
|
||||||
|
width: chairWidth,
|
||||||
|
height: chairHeight,
|
||||||
|
properties: {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set template
|
||||||
|
setTemplate(template: SeatingTemplate): void {
|
||||||
|
this.template = template;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set table spacing
|
||||||
|
setTableSpacing(spacing: number): void {
|
||||||
|
this.tableSpacing = spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set chair spacing
|
||||||
|
setChairSpacing(spacing: number): void {
|
||||||
|
this.chairSpacing = spacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { SeatingTemplateTool };
|
||||||
Reference in New Issue
Block a user