mirror of
https://github.com/janishutz/libreevent.git
synced 2025-11-25 13:24:24 +00:00
finished seats of seatplan editor
This commit is contained in:
@@ -10,33 +10,51 @@
|
||||
<template>
|
||||
<div id="properties">
|
||||
<h2>Properties</h2>
|
||||
<table>
|
||||
<table v-if="active">
|
||||
<tr>
|
||||
<td>Position X:</td>
|
||||
<td><div v-if="!isEditing.x" @dblclick="activateEditing( 'x' )">{{ posSize.x }}px</div>
|
||||
<input v-else type="number" min="20" v-model="internal.x" @focusout="resubmit( 'x' )"></td>
|
||||
<td>
|
||||
<input type="number" min="20" v-model="internal[ active ].x" @focusout="resubmit()">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Position Y:</td>
|
||||
<td><div v-if="!isEditing.y" @dblclick="activateEditing( 'y' )">{{ posSize.y }}px</div>
|
||||
<input v-else type="number" min="20" v-model="internal.y" @focusout="resubmit( 'y' )"></td>
|
||||
<td>
|
||||
<input type="number" min="20" v-model="internal[ active ].y" @focusout="resubmit()">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Width:</td>
|
||||
<td><div v-if="!isEditing.w" @dblclick="activateEditing( 'w' )">{{ posSize.w }}px</div>
|
||||
<input v-else type="number" min="20" v-model="internal.w" @focusout="resubmit( 'w' )"></td>
|
||||
<td>
|
||||
<input type="number" min="20" v-model="internal[ active ].w" @focusout="resubmit()">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Height:</td>
|
||||
<td><div v-if="!isEditing.h" @dblclick="activateEditing( 'h' )">{{ posSize.h }}px</div>
|
||||
<input v-else type="number" min="20" v-model="internal.w" @focusout="resubmit( 'h' )"></td>
|
||||
<td>
|
||||
<input type="number" min="20" v-model="internal[ active ].h" @focusout="resubmit()">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Origin:</td>
|
||||
<td><div v-if="!isEditing.origin" @dblclick="activateEditing( 'origin' )">{{ posSize.origin }}</div>
|
||||
<input v-else type="number" min="20" v-model="internal.origin" @focusout="resubmit( 'origin' )"></td>
|
||||
<td>
|
||||
<input type="number" min="1" max="4" v-model="internal[ active ].origin" @focusout="resubmit()">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Shape:</td>
|
||||
<td><select min="20" v-model="internal[ active ].shape" @change="resubmit()">
|
||||
<option value="rectangular">Rectangular</option>
|
||||
<option value="trapezoid">Trapezoid</option>
|
||||
<option value="circular">Circular</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div v-else class="no-select">
|
||||
<b>No Object selected</b><br>
|
||||
Please select one to view details here.
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -44,38 +62,44 @@
|
||||
export default {
|
||||
name: 'propertiesSeatplan',
|
||||
props: {
|
||||
posSize: {
|
||||
draggables: {
|
||||
type: Object,
|
||||
"default": { 'x': 100, 'y': 100, 'w': 200, 'h': 100, 'origin': 1 }
|
||||
"default": {}
|
||||
},
|
||||
scaleFactor: {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
},
|
||||
active: {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isEditing: { 'w':false },
|
||||
internal: { 'x': 100, 'y': 100, 'w': 200, 'h': 100 },
|
||||
internal: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
activateEditing ( option ) {
|
||||
this.isEditing[ option ] = true;
|
||||
for ( let value in this.posSize ) {
|
||||
this.internal[ value ] = this.posSize[ value ];
|
||||
loadInternal () {
|
||||
for ( let value in this.draggables ) {
|
||||
this.internal[ value ] = this.draggables[ value ];
|
||||
}
|
||||
},
|
||||
resubmit ( option ) {
|
||||
console.log( 'ok' );
|
||||
this.isEditing[ option ] = false;
|
||||
this.$emit( 'updated', this.internal )
|
||||
resubmit () {
|
||||
this.$emit( 'updated', this.internal );
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
posSize() {
|
||||
console.log( 'posSize changed' );
|
||||
draggables ( value ) {
|
||||
this.loadInternal();
|
||||
},
|
||||
active ( value ) {
|
||||
this.loadInternal();
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.loadInternal();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -9,13 +9,15 @@
|
||||
|
||||
<template>
|
||||
<div id="window">
|
||||
<properties class="properties" v-model:posSize="selectedObject" @updated="handleUpdate" :scale-factor="scaleFactor"></properties>
|
||||
<properties class="properties" v-model:draggables="draggables" @updated="handleUpdate" :scale-factor="scaleFactor" :active="active"></properties>
|
||||
<div class="parent">
|
||||
<div class="content-parent">
|
||||
<Vue3DraggableResizable v-for="draggable in draggables" :initW="draggable.w" :initH="draggable.h" v-model:x="draggable.x" v-model:y="draggable.y" v-model:w="draggable.w" v-model:h="draggable.h"
|
||||
v-model:active="draggable.active" :draggable="draggable.draggable" :resizable="draggable.resizable" :parent="true" @activated="activateComponent( draggable.id );"
|
||||
@drag-end="saveHistory();" @resize-end="saveHistory();" @contextmenu="( e ) => { e.preventDefault(); }" class="draggable-box">
|
||||
<circularSeatplanComponent :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin"></circularSeatplanComponent>
|
||||
<circularSeatplanComponent v-if="draggable.shape == 'circular' && draggable.kind == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin"></circularSeatplanComponent>
|
||||
<trapezoidSeatplanComponent v-if="draggable.shape == 'trapezoid' && draggable.kind == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin"></trapezoidSeatplanComponent>
|
||||
<rectangularSeatplanComponent v-if="draggable.shape == 'rectangular' && draggable.kind == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin"></rectangularSeatplanComponent>
|
||||
</Vue3DraggableResizable>
|
||||
</div>
|
||||
</div>
|
||||
@@ -34,6 +36,8 @@
|
||||
import Vue3DraggableResizable from 'vue3-draggable-resizable';
|
||||
import properties from '@/components/seatplan/editor/properties.vue';
|
||||
import circularSeatplanComponent from '@/components/seatplan/seatplanComponents/seats/circular.vue';
|
||||
import rectangularSeatplanComponent from '@/components/seatplan/seatplanComponents/seats/rectangular.vue';
|
||||
import trapezoidSeatplanComponent from '@/components/seatplan/seatplanComponents/seats/trapezoid.vue';
|
||||
import 'vue3-draggable-resizable/dist/Vue3DraggableResizable.css';
|
||||
|
||||
export default {
|
||||
@@ -42,13 +46,14 @@
|
||||
Vue3DraggableResizable,
|
||||
properties,
|
||||
circularSeatplanComponent,
|
||||
rectangularSeatplanComponent,
|
||||
trapezoidSeatplanComponent,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
active: 0,
|
||||
draggables: { 1: { 'x': 100, 'y':100, 'h': 100, 'w': 250, 'active': false, 'draggable': true, 'resizable': true, 'id': 1, 'origin': 1, 'categories': { 1: 0 } } },
|
||||
draggables: { 1: { 'x': 100, 'y':100, 'h': 100, 'w': 250, 'active': false, 'draggable': true, 'resizable': true, 'id': 1, 'origin': 1, 'categories': { 1: 0 }, 'shape':'rectangular', 'kind': 'seat' } },
|
||||
available: { 'redo': false, 'undo': false },
|
||||
selectedObject: {},
|
||||
scaleFactor: 1,
|
||||
sizePoll: null,
|
||||
prevSize: { 'h': window.innerHeight, 'w': window.innerWidth },
|
||||
@@ -139,7 +144,7 @@
|
||||
|
||||
for ( let element in this.draggables ) {
|
||||
if ( this.draggables[ element ].active ) {
|
||||
this.activateComponent( element );
|
||||
this.draggables[ element ].active = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -174,9 +179,7 @@
|
||||
return returnArray;
|
||||
},
|
||||
activateComponent ( id ) {
|
||||
console.log( id );
|
||||
this.active = id;
|
||||
this.selectedObject = this.draggables[ this.active ];
|
||||
},
|
||||
saveHistory () {
|
||||
let history = sessionStorage.getItem( 'seatplan-history' ) ? JSON.parse( sessionStorage.getItem( 'seatplan-history' ) ) : {};
|
||||
@@ -228,7 +231,7 @@
|
||||
sessionStorage.setItem( 'seatplan', JSON.stringify( this.scaleDown( this.draggables ) ) );
|
||||
},
|
||||
addNewElement () {
|
||||
this.draggables[ Object.keys( this.draggables ).length + 1 ] = { 'x': 100, 'y':100, 'h': 100, 'w': 250, 'active': false, 'draggable': true, 'resizable': true, 'id': Object.keys( this.draggables ).length + 1, 'origin': 1, 'categories': { 1: 0 } };
|
||||
this.draggables[ Object.keys( this.draggables ).length + 1 ] = { 'x': 100, 'y':100, 'h': 100, 'w': 250, 'active': false, 'draggable': true, 'resizable': true, 'id': Object.keys( this.draggables ).length + 1, 'origin': 1, 'categories': { 1: 0 }, 'shape':'rectangular', 'kind': 'seat' };
|
||||
this.saveHistory();
|
||||
},
|
||||
deleteSelected () {
|
||||
@@ -239,7 +242,7 @@
|
||||
}
|
||||
},
|
||||
handleUpdate ( value ) {
|
||||
this.draggables[ this.active ] = value;
|
||||
this.draggables = value;
|
||||
this.selectedObject = value;
|
||||
this.saveHistory();
|
||||
}
|
||||
@@ -250,7 +253,7 @@
|
||||
},
|
||||
unmounted() {
|
||||
clearInterval( this.sizePoll );
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -269,7 +272,6 @@
|
||||
}
|
||||
|
||||
.draggable-box {
|
||||
border: black 1px solid;
|
||||
cursor: all-scroll;
|
||||
}
|
||||
|
||||
@@ -290,6 +292,6 @@
|
||||
|
||||
.content-parent {
|
||||
aspect-ratio: 16 / 9;
|
||||
height: 3000px;
|
||||
height: 400%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
<template>
|
||||
<div id="circularSeatplan">
|
||||
<div v-for="row in seats">
|
||||
<div v-for="seat in row">
|
||||
<span class="material-symbols-outlined seats" :style="seat.style">living</span>
|
||||
</div>
|
||||
<span class="material-symbols-outlined seats" v-for="seat in row" :style="seat.style">living</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -55,7 +53,7 @@ export default {
|
||||
// w & h are normalised
|
||||
let w = Math.round( this.w / this.scaleFactor );
|
||||
let h = Math.round( this.h / this.scaleFactor );
|
||||
const size = 37;
|
||||
const size = 33;
|
||||
let count = Math.min( Math.floor( w / size ), Math.floor( h / size ) );
|
||||
this.seats = {};
|
||||
for ( let row = 0; row < count; row++ ) {
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
<!--
|
||||
* myevent - properties.vue
|
||||
*
|
||||
* Created by Janis Hutz 05/12/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div id="rectangularSeatplan">
|
||||
<div v-for="row in seats" class="rows">
|
||||
<span class="material-symbols-outlined seats" v-for="seat in row" :style="seat.style">living</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.seats {
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'rectangularSeatplanComponent',
|
||||
props: {
|
||||
h: {
|
||||
type: Number,
|
||||
"default": 100,
|
||||
},
|
||||
w: {
|
||||
type: Number,
|
||||
"default": 200,
|
||||
},
|
||||
scaleFactor: {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
},
|
||||
origin: {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
seats: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
calculateChairs () {
|
||||
// Size of seat at scale 1 is 32px
|
||||
// w & h are normalised
|
||||
let w = Math.floor( this.w / this.scaleFactor );
|
||||
let h = Math.floor( this.h / this.scaleFactor );
|
||||
const size = 33;
|
||||
this.seats = {};
|
||||
for ( let row = 0; row < Math.floor( h / size ); row++ ) {
|
||||
this.seats[ row ] = {};
|
||||
for ( let n = 0; n < Math.floor( w / size ); n++ ) {
|
||||
if ( this.origin === 1 ) {
|
||||
this.seats[ row ][ n ] = { 'style': `font-size: ${this.scaleFactor * 200}%; bottom: ${ row * size * this.scaleFactor }px; left: ${ n * size * this.scaleFactor }px; rotate: ${ this.origin / 4 - 0.25 }turn;` };
|
||||
} else if ( this.origin === 2 ) {
|
||||
this.seats[ row ][ n ] = { 'style': `font-size: ${this.scaleFactor * 200}%; bottom: ${ row * size * this.scaleFactor }px; right: ${ n * size * this.scaleFactor }px; rotate: ${ this.origin / 4 - 0.25 }turn;` };
|
||||
} else if ( this.origin === 3 ) {
|
||||
this.seats[ row ][ n ] = { 'style': `font-size: ${this.scaleFactor * 200}%; top: ${ row * size * this.scaleFactor }px; right: ${ n * size * this.scaleFactor }px; rotate: ${ this.origin / 4 - 0.25 }turn;` };
|
||||
} else if ( this.origin === 4 ) {
|
||||
this.seats[ row ][ n ] = { 'style': `font-size: ${this.scaleFactor * 200}%; top: ${ row * size * this.scaleFactor }px; left: ${ n * size * this.scaleFactor }px; rotate: ${ this.origin / 4 - 0.25 }turn;` };
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
setScaleFactor () {
|
||||
for ( let row in this.seats ) {
|
||||
for ( let seat in this.seats[ row ] ) {
|
||||
let styles = this.seats[ row ][ seat ].style.substring( this.seats[ row ][ seat ].style.indexOf( ';' ) + 1 );
|
||||
this.seats[ row ][ seat ].style = `font-size: ${this.scaleFactor * 200}%;` + styles;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
scaleFactor() {
|
||||
this.setScaleFactor();
|
||||
},
|
||||
h() {
|
||||
this.calculateChairs();
|
||||
},
|
||||
w() {
|
||||
this.calculateChairs();
|
||||
},
|
||||
origin() {
|
||||
this.calculateChairs();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.calculateChairs();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
<!--
|
||||
* myevent - properties.vue
|
||||
*
|
||||
* Created by Janis Hutz 05/12/2023, Licensed under the GPL V3 License
|
||||
* https://janishutz.com, development@janishutz.com
|
||||
*
|
||||
*
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div id="trapezoidSeatplan">
|
||||
<div v-for="row in seats">
|
||||
<span class="material-symbols-outlined seats" v-for="seat in row" :style="seat.style">living</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.seats {
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'trapezoidSeatplanComponent',
|
||||
props: {
|
||||
h: {
|
||||
type: Number,
|
||||
"default": 100,
|
||||
},
|
||||
w: {
|
||||
type: Number,
|
||||
"default": 200,
|
||||
},
|
||||
scaleFactor: {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
},
|
||||
origin: {
|
||||
type: Number,
|
||||
"default": 1,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
seats: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
calculateChairs () {
|
||||
// Size of seat at scale 1 is 32px
|
||||
// w & h are normalised
|
||||
let w = Math.round( this.w / this.scaleFactor );
|
||||
let h = Math.round( this.h / this.scaleFactor );
|
||||
const size = 33;
|
||||
let side = Math.min( w, h ) + 20;
|
||||
let heightTriangle = Math.floor( Math.sqrt( side ** 2 - ( Math.sqrt( side ** 2 * 2 ) / 2 ) ) )
|
||||
let sideOffset = size / Math.sqrt( 2 );
|
||||
let count = Math.floor( heightTriangle / ( sideOffset * 2 ) );
|
||||
const angle = Math.PI / 4;
|
||||
this.seats = {};
|
||||
for ( let row = 0; row < count; row++ ) {
|
||||
let nn = 2 + ( row - 1 ) * 2;
|
||||
this.seats[ row ] = {};
|
||||
for ( let n = 0; n < nn; n++ ) {
|
||||
let side = n * sideOffset;
|
||||
if ( this.origin === 1 ) {
|
||||
this.seats[ row ][ n ] = { 'style': `font-size: ${this.scaleFactor * 200}%; bottom: ${ ( side + 5 ) * this.scaleFactor }px; left: ${ ( row * sideOffset * 2 - side ) * this.scaleFactor }px; rotate: ${ angle }rad` };
|
||||
} else if ( this.origin === 2 ) {
|
||||
this.seats[ row ][ n ] = { 'style': `font-size: ${this.scaleFactor * 200}%; bottom: ${ ( side + 5 ) * this.scaleFactor }px; right: ${ ( row * size - side ) * this.scaleFactor }px; rotate: ${ Math.PI * 2 - angle }rad` };
|
||||
} else if ( this.origin === 3 ) {
|
||||
this.seats[ row ][ n ] = { 'style': `font-size: ${this.scaleFactor * 200}%; top: ${ ( side + 5 ) * this.scaleFactor }px; right: ${ ( row * size - side ) * this.scaleFactor }px; rotate: ${ angle + Math.PI }rad` };
|
||||
} else if ( this.origin === 4 ) {
|
||||
this.seats[ row ][ n ] = { 'style': `font-size: ${this.scaleFactor * 200}%; top: ${ ( side + 5 ) * this.scaleFactor }px; left: ${ ( row * size - side ) * this.scaleFactor }px; rotate: ${ Math.PI - angle }rad` };
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
setScaleFactor () {
|
||||
for ( let row in this.seats ) {
|
||||
for ( let seat in this.seats[ row ] ) {
|
||||
let styles = this.seats[ row ][ seat ].style.substring( this.seats[ row ][ seat ].style.indexOf( ';' ) + 1 );
|
||||
this.seats[ row ][ seat ].style = `font-size: ${this.scaleFactor * 200}%;` + styles;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
scaleFactor() {
|
||||
this.setScaleFactor();
|
||||
},
|
||||
h() {
|
||||
this.calculateChairs();
|
||||
},
|
||||
w() {
|
||||
this.calculateChairs();
|
||||
},
|
||||
origin() {
|
||||
this.calculateChairs();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.calculateChairs();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user