mirror of
https://github.com/janishutz/libreevent.git
synced 2025-11-25 05:14:23 +00:00
user facing seat plan
This commit is contained in:
@@ -0,0 +1,119 @@
|
|||||||
|
<!--
|
||||||
|
* libreevent - properties.vue
|
||||||
|
*
|
||||||
|
* Created by Janis Hutz 05/12/2023, Licensed under the GPL V3 License
|
||||||
|
* https://janishutz.com, development@janishutz.com
|
||||||
|
*
|
||||||
|
*
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="circularSeatplan">
|
||||||
|
<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: 'circularSeatplanComponent',
|
||||||
|
props: {
|
||||||
|
h: {
|
||||||
|
type: Number,
|
||||||
|
"default": 100,
|
||||||
|
},
|
||||||
|
w: {
|
||||||
|
type: Number,
|
||||||
|
"default": 200,
|
||||||
|
},
|
||||||
|
scaleFactor: {
|
||||||
|
type: Number,
|
||||||
|
"default": 1,
|
||||||
|
},
|
||||||
|
origin: {
|
||||||
|
type: Number,
|
||||||
|
"default": 1,
|
||||||
|
},
|
||||||
|
startingRow: {
|
||||||
|
type: Number,
|
||||||
|
"default": 1,
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
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 count = Math.min( Math.floor( w / size ), Math.floor( h / size ) );
|
||||||
|
this.seats = {};
|
||||||
|
let details = { 'data': {}, 'id': this.id };
|
||||||
|
for ( let row = this.startingRow; row < count; row++ ) {
|
||||||
|
let nn = row * ( Math.PI / 2 );
|
||||||
|
details.data[ row ] = Math.floor( nn );
|
||||||
|
let r = row * size;
|
||||||
|
this.seats[ row ] = {};
|
||||||
|
for ( let n = 0; n < nn; n++ ) {
|
||||||
|
let phi = n * size / ( row * size );
|
||||||
|
if ( this.origin === 1 ) {
|
||||||
|
this.seats[ row ][ n ] = { 'style': `font-size: ${this.scaleFactor * 200}%; bottom: ${ r * Math.cos( phi ) * this.scaleFactor }px; left: ${ r * Math.sin( phi ) * this.scaleFactor }px; rotate: ${ phi }rad` };
|
||||||
|
} else if ( this.origin === 2 ) {
|
||||||
|
this.seats[ row ][ n ] = { 'style': `font-size: ${this.scaleFactor * 200}%; bottom: ${ r * Math.cos( phi ) * this.scaleFactor }px; right: ${ r * Math.sin( phi ) * this.scaleFactor }px; rotate: ${ Math.PI * 2 - phi }rad` };
|
||||||
|
} else if ( this.origin === 3 ) {
|
||||||
|
this.seats[ row ][ n ] = { 'style': `font-size: ${this.scaleFactor * 200}%; top: ${ r * Math.cos( phi ) * this.scaleFactor }px; right: ${ r * Math.sin( phi ) * this.scaleFactor }px; rotate: ${ phi + Math.PI }rad` };
|
||||||
|
} else if ( this.origin === 4 ) {
|
||||||
|
this.seats[ row ][ n ] = { 'style': `font-size: ${this.scaleFactor * 200}%; top: ${ r * Math.cos( phi ) * this.scaleFactor }px; left: ${ r * Math.sin( phi ) * this.scaleFactor }px; rotate: ${ Math.PI - phi }rad` };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$emit( 'seatingInfo', details );
|
||||||
|
},
|
||||||
|
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();
|
||||||
|
},
|
||||||
|
startingRow() {
|
||||||
|
this.calculateChairs();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.calculateChairs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
<!--
|
||||||
|
* libreevent - 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" @click="selectSeat( seat.id )">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,
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
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,122 @@
|
|||||||
|
<!--
|
||||||
|
* libreevent - 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,
|
||||||
|
},
|
||||||
|
startingRow: {
|
||||||
|
type: Number,
|
||||||
|
"default": 1,
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
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 = {};
|
||||||
|
let details = { 'data': {}, 'id': this.id };
|
||||||
|
for ( let row = this.startingRow; row < count; row++ ) {
|
||||||
|
let nn = 2 + ( row - 1 ) * 2;
|
||||||
|
this.seats[ row ] = {};
|
||||||
|
details.data[ row ] = Math.floor( nn );
|
||||||
|
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 * sideOffset * 2 - 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 * sideOffset * 2 - 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 * sideOffset * 2 - side ) * this.scaleFactor }px; rotate: ${ Math.PI - angle }rad` };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$emit( 'seatingInfo', details );
|
||||||
|
},
|
||||||
|
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();
|
||||||
|
},
|
||||||
|
startingRow() {
|
||||||
|
this.calculateChairs();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.calculateChairs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
<!--
|
||||||
|
* libreevent - stages.vue
|
||||||
|
*
|
||||||
|
* Created by Janis Hutz 05/12/2023, Licensed under the GPL V3 License
|
||||||
|
* https://janishutz.com, development@janishutz.com
|
||||||
|
*
|
||||||
|
*
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="stages" class="stages">
|
||||||
|
<div id="rectangular" v-if="shape == 'rectangular'" class="stages" :style="style"></div>
|
||||||
|
<div id="trapezoid" v-else-if="shape == 'trapezoid'" class="stages"><div id="trapezoid-ingredient" :style="trapezoidStyle"><div id="trapezoid-line"></div></div></div>
|
||||||
|
<div id="circular" v-else-if="shape == 'circular'" class="stages"><div id="circular-ingredient" :style="circularStyle"></div></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.stages {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rectangular {
|
||||||
|
border-color: black;
|
||||||
|
border-width: 2px;
|
||||||
|
background-color: var( --popup-color );
|
||||||
|
}
|
||||||
|
|
||||||
|
#circular, #trapezoid {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#trapezoid-ingredient {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-end;
|
||||||
|
height: 200%;
|
||||||
|
width: 200%;
|
||||||
|
position: relative;
|
||||||
|
bottom: 50%;
|
||||||
|
right: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#trapezoid-line {
|
||||||
|
border: black solid 1px;
|
||||||
|
height: 50%;
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
background-color: var( --popup-color );
|
||||||
|
}
|
||||||
|
|
||||||
|
#circular-ingredient {
|
||||||
|
border: solid black 2px;
|
||||||
|
border-radius: 100%;
|
||||||
|
height: 199%;
|
||||||
|
width: 199%;
|
||||||
|
position: relative;
|
||||||
|
background-color: var( --popup-color );
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'stagesSeatplanComponent',
|
||||||
|
props: {
|
||||||
|
origin: {
|
||||||
|
type: Number,
|
||||||
|
"default": 1,
|
||||||
|
},
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
"default": "rectangular",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
style: 'border-style: none none solid none',
|
||||||
|
circularStyle: 'top: 0; left 100%;',
|
||||||
|
trapezoidStyle: 'rotate: 45deg',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateOrigin () {
|
||||||
|
if ( this.origin === 1 ) {
|
||||||
|
this.style = 'border-style: none none solid none';
|
||||||
|
this.circularStyle = 'top: 0; right: 100%;';
|
||||||
|
} else if ( this.origin === 2 ) {
|
||||||
|
this.style = 'border-style: none solid none none';
|
||||||
|
this.circularStyle = 'top: 0; right: 0;';
|
||||||
|
} else if ( this.origin === 3 ) {
|
||||||
|
this.style = 'border-style: solid none none none';
|
||||||
|
this.circularStyle = 'top: -100%; right: 0;';
|
||||||
|
} else if ( this.origin === 4 ) {
|
||||||
|
this.style = 'border-style: none none none solid';
|
||||||
|
this.circularStyle = 'top: -100%; right: 100%;';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
origin ( value ) {
|
||||||
|
this.updateOrigin();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.updateOrigin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
<!--
|
||||||
|
* libreevent - standing.vue
|
||||||
|
*
|
||||||
|
* Created by Janis Hutz 05/12/2023, Licensed under the GPL V3 License
|
||||||
|
* https://janishutz.com, development@janishutz.com
|
||||||
|
*
|
||||||
|
*
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="stages" class="stages">
|
||||||
|
<div id="rectangular" v-if="shape == 'rectangular'" class="stages" :style="style"></div>
|
||||||
|
<div id="trapezoid" v-else-if="shape == 'trapezoid'" class="stages"><div id="trapezoid-ingredient" :style="trapezoidStyle"><div id="trapezoid-line"></div></div></div>
|
||||||
|
<div id="circular" v-else-if="shape == 'circular'" class="stages"><div id="circular-ingredient" :style="circularStyle"></div></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.stages {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rectangular {
|
||||||
|
border-color: black;
|
||||||
|
border-width: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#circular, #trapezoid {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#trapezoid-ingredient {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 200%;
|
||||||
|
width: 200%;
|
||||||
|
position: relative;
|
||||||
|
bottom: 50%;
|
||||||
|
right: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#trapezoid-line {
|
||||||
|
border: black solid 1px;
|
||||||
|
height: 50%;
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
background-color: var( --popup-color );
|
||||||
|
}
|
||||||
|
|
||||||
|
#circular-ingredient {
|
||||||
|
border: solid black 2px;
|
||||||
|
border-radius: 100%;
|
||||||
|
height: 199%;
|
||||||
|
width: 199%;
|
||||||
|
position: relative;
|
||||||
|
background-color: var( --popup-color );
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'stagesSeatplanComponent',
|
||||||
|
props: {
|
||||||
|
origin: {
|
||||||
|
type: Number,
|
||||||
|
"default": 1,
|
||||||
|
},
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
"default": "rectangular",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
style: 'border-style: none none solid none',
|
||||||
|
circularStyle: 'top: 0; left 100%;',
|
||||||
|
trapezoidStyle: 'rotate: 45deg',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateOrigin () {
|
||||||
|
if ( this.origin === 1 ) {
|
||||||
|
this.style = 'border-style: none none solid none';
|
||||||
|
this.circularStyle = 'top: 0; right: 100%;';
|
||||||
|
} else if ( this.origin === 2 ) {
|
||||||
|
this.style = 'border-style: none solid none none';
|
||||||
|
this.circularStyle = 'top: 0; right: 0;';
|
||||||
|
} else if ( this.origin === 3 ) {
|
||||||
|
this.style = 'border-style: solid none none none';
|
||||||
|
this.circularStyle = 'top: -100%; right: 0;';
|
||||||
|
} else if ( this.origin === 4 ) {
|
||||||
|
this.style = 'border-style: none none none solid';
|
||||||
|
this.circularStyle = 'top: -100%; right: 100%;';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
origin ( value ) {
|
||||||
|
this.updateOrigin();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.updateOrigin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
<!--
|
||||||
|
* libreevent - textField.vue
|
||||||
|
*
|
||||||
|
* Created by Janis Hutz 07/01/2023, Licensed under the GPL V3 License
|
||||||
|
* https://janishutz.com, development@janishutz.com
|
||||||
|
*
|
||||||
|
*
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="textFields">
|
||||||
|
<p :style="style">{{ text }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'textFieldSeatplanComponent',
|
||||||
|
props: {
|
||||||
|
origin: {
|
||||||
|
type: Number,
|
||||||
|
"default": 1,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
"default": "Untitled",
|
||||||
|
},
|
||||||
|
textSize: {
|
||||||
|
type: Number,
|
||||||
|
"default": 20,
|
||||||
|
},
|
||||||
|
scaleFactor: {
|
||||||
|
type: Number,
|
||||||
|
"default": 1,
|
||||||
|
},
|
||||||
|
colour: {
|
||||||
|
type: String,
|
||||||
|
"default": '#000000',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
style: 'font-size: 20pt; rotate: 0deg; color: #000000',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateStyle () {
|
||||||
|
this.style = `font-size: ${ this.scaleFactor * this.textSize }pt; rotate: ${ 90 * this.origin - 90 }deg; color: ${this.colour}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
origin ( value ) {
|
||||||
|
this.updateStyle();
|
||||||
|
},
|
||||||
|
scaleFactor ( value ) {
|
||||||
|
this.updateStyle();
|
||||||
|
},
|
||||||
|
colour ( value ) {
|
||||||
|
this.updateStyle();
|
||||||
|
},
|
||||||
|
textSize ( value ) {
|
||||||
|
this.updateStyle();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.updateStyle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -9,11 +9,11 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="window">
|
<div id="window">
|
||||||
<!-- TODO: Add additional div with v-if to check if a location has been selected and warn if not so. -->
|
<h2>Seat plan: {{ event.name }}</h2>
|
||||||
<div class="parent" id="parent">
|
<div class="parent" id="parent" @wheel="( e ) => { handleScroll( e ); }" @mousemove="( e ) => { handleDrag( e ); }" @mousedown="( e ) => { setOffset( e ); }">
|
||||||
<div class="content-parent">
|
<div class="content-parent">
|
||||||
<Vue3DraggableResizable v-for="draggable in draggables" :initW="draggable.w" :initH="draggable.h" :x="draggable.x" :y="draggable.y" :w="draggable.w" :h="draggable.h"
|
<Vue3DraggableResizable v-for="draggable in draggables" :initW="draggable.w" :initH="draggable.h" :x="draggable.x" :y="draggable.y" :w="draggable.w" :h="draggable.h"
|
||||||
:active="false" :draggable="false" :resizable="false" :parent="true" @contextmenu="( e ) => { e.preventDefault(); }" class="draggable-box">
|
:active="false" :draggable="false" :resizable="false" :parent="true" class="draggable-box">
|
||||||
<circularSeatplanComponent v-if="draggable.shape == 'circular' && draggable.type == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin" :starting-row="draggable.startingRow"></circularSeatplanComponent>
|
<circularSeatplanComponent v-if="draggable.shape == 'circular' && draggable.type == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin" :starting-row="draggable.startingRow"></circularSeatplanComponent>
|
||||||
<trapezoidSeatplanComponent v-else-if="draggable.shape == 'trapezoid' && draggable.type == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin" :starting-row="draggable.startingRow"></trapezoidSeatplanComponent>
|
<trapezoidSeatplanComponent v-else-if="draggable.shape == 'trapezoid' && draggable.type == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin" :starting-row="draggable.startingRow"></trapezoidSeatplanComponent>
|
||||||
<rectangularSeatplanComponent v-else-if="draggable.shape == 'rectangular' && draggable.type == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin"></rectangularSeatplanComponent>
|
<rectangularSeatplanComponent v-else-if="draggable.shape == 'rectangular' && draggable.type == 'seat'" :scale-factor="scaleFactor" :w="draggable.w" :h="draggable.h" :origin="draggable.origin"></rectangularSeatplanComponent>
|
||||||
@@ -23,18 +23,23 @@
|
|||||||
</Vue3DraggableResizable>
|
</Vue3DraggableResizable>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="toolbar">
|
||||||
|
<button title="Zoom in [+]" @click="zoom( 0.2 )"><span class="material-symbols-outlined">zoom_in</span></button>
|
||||||
|
<button title="Reset zoom [=]" @click="zoom( 1 );"><span class="material-symbols-outlined">center_focus_strong</span></button>
|
||||||
|
<button title="Zoom out [-]" @click="zoom( -0.2 )"><span class="material-symbols-outlined">zoom_out</span></button>
|
||||||
|
</div>
|
||||||
<notifications ref="notification" location="topleft"></notifications>
|
<notifications ref="notification" location="topleft"></notifications>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Vue3DraggableResizable from 'vue3-draggable-resizable';
|
import Vue3DraggableResizable from 'vue3-draggable-resizable';
|
||||||
import circularSeatplanComponent from '@/components/seatplan/seatplanComponents/seats/circular.vue';
|
import circularSeatplanComponent from '@/components/seatplan/userApp/seatplanComponents/seats/circular.vue';
|
||||||
import rectangularSeatplanComponent from '@/components/seatplan/seatplanComponents/seats/rectangular.vue';
|
import rectangularSeatplanComponent from '@/components/seatplan/userApp/seatplanComponents/seats/rectangular.vue';
|
||||||
import trapezoidSeatplanComponent from '@/components/seatplan/seatplanComponents/seats/trapezoid.vue';
|
import trapezoidSeatplanComponent from '@/components/seatplan/userApp/seatplanComponents/seats/trapezoid.vue';
|
||||||
import stagesSeatplanComponent from '@/components/seatplan/seatplanComponents/stages.vue';
|
import stagesSeatplanComponent from '@/components/seatplan/userApp/seatplanComponents/stages.vue';
|
||||||
import standingSeatplanComponent from '@/components/seatplan/seatplanComponents/standing.vue';
|
import standingSeatplanComponent from '@/components/seatplan/userApp/seatplanComponents/standing.vue';
|
||||||
import textFieldSeatplanComponent from '@/components/seatplan/seatplanComponents/textField.vue';
|
import textFieldSeatplanComponent from '@/components/seatplan/userApp/seatplanComponents/textField.vue';
|
||||||
import notifications from '@/components/notifications/notifications.vue';
|
import notifications from '@/components/notifications/notifications.vue';
|
||||||
import 'vue3-draggable-resizable/dist/Vue3DraggableResizable.css';
|
import 'vue3-draggable-resizable/dist/Vue3DraggableResizable.css';
|
||||||
|
|
||||||
@@ -54,12 +59,14 @@
|
|||||||
return {
|
return {
|
||||||
active: 0,
|
active: 0,
|
||||||
draggables: { 1: { 'x': 100, 'y':100, 'h': 100, 'w': 250, 'active': false, 'draggable': true, 'resizable': true, 'id': 1, 'origin': 1, 'shape':'rectangular', 'type': 'seat', 'startingRow': 1, 'seatCountingStartingPoint': 1, 'sector': 'A', 'text': { 'text': 'TestText', 'textSize': 20, 'colour': '#20FFFF' } }, 'ticketCount': 1 },
|
draggables: { 1: { 'x': 100, 'y':100, 'h': 100, 'w': 250, 'active': false, 'draggable': true, 'resizable': true, 'id': 1, 'origin': 1, 'shape':'rectangular', 'type': 'seat', 'startingRow': 1, 'seatCountingStartingPoint': 1, 'sector': 'A', 'text': { 'text': 'TestText', 'textSize': 20, 'colour': '#20FFFF' } }, 'ticketCount': 1 },
|
||||||
|
event: { 'name': 'TestEvent2', 'location': 'TestLocation2', 'date': '2023-07-15', 'RoomName': 'TestRoom2', 'currency': 'CHF', 'categories': { '1': { 'price': { '1':25, '2':35 }, 'bg': 'black', 'fg': 'white', 'name': 'Category 1' }, '2': { 'price': { '1':15, '2':20 }, 'bg': 'green', 'fg': 'white', 'name': 'Category 2' } }, 'ageGroups': { '1':{ 'id': 1, 'name':'Child', 'age':'0 - 15.99' }, '2':{ 'id': 2, 'name': 'Adult', 'age': null } }, 'ageGroupCount': 2, 'maxTickets': 2 },
|
||||||
available: { 'redo': false, 'undo': false },
|
available: { 'redo': false, 'undo': false },
|
||||||
scaleFactor: 1,
|
scaleFactor: 1,
|
||||||
sizePoll: null,
|
sizePoll: null,
|
||||||
prevSize: { 'h': window.innerHeight, 'w': window.innerWidth },
|
prevSize: { 'h': window.innerHeight, 'w': window.innerWidth },
|
||||||
zoomFactor: 1,
|
zoomFactor: 1,
|
||||||
historyPos: 0,
|
standardDeviation: { 'currentTop': 0, 'currentLeft': 0 },
|
||||||
|
movePos: { 'top': 0, 'left': 0, 'isMoving': false, 'isSet': false },
|
||||||
generalSettings: { 'namingScheme': 'numeric' },
|
generalSettings: { 'namingScheme': 'numeric' },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -85,22 +92,7 @@
|
|||||||
- Ctrl + Y: Redo
|
- Ctrl + Y: Redo
|
||||||
*/
|
*/
|
||||||
document.onkeydown = function ( event ) {
|
document.onkeydown = function ( event ) {
|
||||||
if ( event.key === 'Delete' ) {
|
if ( event.key === '+' ) {
|
||||||
event.preventDefault();
|
|
||||||
self.deleteSelected();
|
|
||||||
} else if ( event.ctrlKey && event.key === 's' ) {
|
|
||||||
event.preventDefault();
|
|
||||||
self.saveDraft();
|
|
||||||
} else if ( ( event.ctrlKey && event.key === 'y' ) ) {
|
|
||||||
event.preventDefault();
|
|
||||||
self.historyOp( 'redo' );
|
|
||||||
} else if ( event.ctrlKey && event.key === 'z' ) {
|
|
||||||
event.preventDefault();
|
|
||||||
self.historyOp( 'undo' );
|
|
||||||
} else if ( event.ctrlKey && event.key === 'i' ) {
|
|
||||||
event.preventDefault();
|
|
||||||
self.addNewElement();
|
|
||||||
} else if ( event.key === '+' ) {
|
|
||||||
self.zoom( 0.2 );
|
self.zoom( 0.2 );
|
||||||
} else if ( event.key === '-' ) {
|
} else if ( event.key === '-' ) {
|
||||||
self.zoom( -0.2 );
|
self.zoom( -0.2 );
|
||||||
@@ -110,7 +102,9 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.loadSeatplan();
|
this.loadSeatplan();
|
||||||
// TODO: Add warning for untested browsers & suboptimal window sizes!
|
sessionStorage.setItem( 'seatplan', JSON.stringify( this.scaleDown( this.draggables ) ) );
|
||||||
|
// TODO: remove scaleDown function again once backend is up
|
||||||
|
// TODO: Optimise for odd screen sizes and aspect ratios
|
||||||
},
|
},
|
||||||
eventHandler ( e ) {
|
eventHandler ( e ) {
|
||||||
if ( this.prevSize.h != window.innerHeight || this.prevSize.w != window.innerWidth ) {
|
if ( this.prevSize.h != window.innerHeight || this.prevSize.w != window.innerWidth ) {
|
||||||
@@ -118,6 +112,56 @@
|
|||||||
this.loadSeatplan();
|
this.loadSeatplan();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
handleScroll ( e ) {
|
||||||
|
e.preventDefault();
|
||||||
|
if ( e.deltaY > 0 ) {
|
||||||
|
this.zoom( 0.2 );
|
||||||
|
} else {
|
||||||
|
this.zoom( -0.2 );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setOffset( e ) {
|
||||||
|
this.standardDeviation.currentLeft = e.clientX;
|
||||||
|
this.standardDeviation.currentTop = e.clientY;
|
||||||
|
},
|
||||||
|
handleDrag ( e ) {
|
||||||
|
if ( e.buttons === 1 ) {
|
||||||
|
let parent = document.getElementById( 'parent' );
|
||||||
|
if ( !this.movePos.isSet ) {
|
||||||
|
this.movePos.left = parent.scrollWidth - parent.scrollLeft;
|
||||||
|
this.movePos.top = parent.scrollHeight - parent.scrollTop;
|
||||||
|
this.movePos.isSet = true;
|
||||||
|
}
|
||||||
|
this.movePos.isMoving = true;
|
||||||
|
e.preventDefault();
|
||||||
|
let valueTop = parent.scrollHeight - ( e.clientY - this.standardDeviation.currentTop + this.movePos.top );
|
||||||
|
let valueLeft = parent.scrollWidth - ( e.clientX - this.standardDeviation.currentLeft + this.movePos.left );
|
||||||
|
parent.scrollTop = valueTop > 0 ? valueTop : 0;
|
||||||
|
parent.scrollLeft = valueLeft > 0 ? valueLeft : 0;
|
||||||
|
} else {
|
||||||
|
if ( this.movePos.isMoving ) {
|
||||||
|
let parent = document.getElementById( 'parent' );
|
||||||
|
this.movePos.left = parent.scrollWidth - parent.scrollLeft;
|
||||||
|
this.movePos.top = parent.scrollHeight - parent.scrollTop;
|
||||||
|
this.movePos.isMoving = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
scaleDown ( valueArray ) {
|
||||||
|
const allowedAttributes = [ 'w', 'h', 'x', 'y' ]
|
||||||
|
let returnArray = {};
|
||||||
|
for ( let entry in valueArray ) {
|
||||||
|
returnArray[ entry ] = {};
|
||||||
|
for ( let attributes in valueArray[ entry ] ) {
|
||||||
|
if ( allowedAttributes.includes( attributes ) ) {
|
||||||
|
returnArray[ entry ][ attributes ] = Math.round( ( valueArray[ entry ][ attributes ] / this.scaleFactor ) * 1000 ) / 1000;
|
||||||
|
} else {
|
||||||
|
returnArray[ entry ][ attributes ] = valueArray[ entry ][ attributes ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnArray;
|
||||||
|
},
|
||||||
loadSeatplan () {
|
loadSeatplan () {
|
||||||
/*
|
/*
|
||||||
Calculate scale factor (this adds support for differently sized screens)
|
Calculate scale factor (this adds support for differently sized screens)
|
||||||
@@ -134,7 +178,6 @@
|
|||||||
this.draggables = this.scaleUp( JSON.parse( sessionStorage.getItem( 'seatplan' ) ) );
|
this.draggables = this.scaleUp( JSON.parse( sessionStorage.getItem( 'seatplan' ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for ( let element in this.draggables ) {
|
for ( let element in this.draggables ) {
|
||||||
if ( this.draggables[ element ].active ) {
|
if ( this.draggables[ element ].active ) {
|
||||||
this.draggables[ element ].active = false;
|
this.draggables[ element ].active = false;
|
||||||
@@ -142,7 +185,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
scaleUp ( valueArray ) {
|
scaleUp ( valueArray ) {
|
||||||
const allowedAttributes = [ 'w', 'h', 'x', 'y' ]
|
const allowedAttributes = [ 'w', 'h', 'x', 'y' ];
|
||||||
let returnArray = {};
|
let returnArray = {};
|
||||||
for ( let entry in valueArray ) {
|
for ( let entry in valueArray ) {
|
||||||
returnArray[ entry ] = {};
|
returnArray[ entry ] = {};
|
||||||
@@ -156,11 +199,6 @@
|
|||||||
}
|
}
|
||||||
return returnArray;
|
return returnArray;
|
||||||
},
|
},
|
||||||
handleUpdate ( value ) {
|
|
||||||
this.draggables = value;
|
|
||||||
this.selectedObject = value;
|
|
||||||
this.saveHistory();
|
|
||||||
},
|
|
||||||
zoom ( scale ) {
|
zoom ( scale ) {
|
||||||
if ( scale == 1 ) {
|
if ( scale == 1 ) {
|
||||||
this.zoomFactor = 1;
|
this.zoomFactor = 1;
|
||||||
@@ -168,11 +206,7 @@
|
|||||||
this.loadSeatplan();
|
this.loadSeatplan();
|
||||||
} else {
|
} else {
|
||||||
if ( ( this.zoomFactor < 0.3 && scale < 0 ) || ( this.zoomFactor > 2.9 && scale > 0 ) ) {
|
if ( ( this.zoomFactor < 0.3 && scale < 0 ) || ( this.zoomFactor > 2.9 && scale > 0 ) ) {
|
||||||
if ( this.zoomFactor < 0.3 ) {
|
|
||||||
this.$refs.notification.createNotification( 'Minimum zoom factor reached', 5, 'warning', 'normal' );
|
|
||||||
} else {
|
|
||||||
this.$refs.notification.createNotification( 'Maximum zoom factor reached', 5, 'warning', 'normal' );
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.zoomFactor += scale;
|
this.zoomFactor += scale;
|
||||||
}
|
}
|
||||||
@@ -193,10 +227,10 @@
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.parent {
|
.parent {
|
||||||
height: 90vh;
|
height: 80vh;
|
||||||
aspect-ratio: 16 / 9;
|
aspect-ratio: 16 / 9;
|
||||||
top: 7.5vh;
|
top: 17vh;
|
||||||
left: 3vw;
|
left: 10vw;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border: black 1px solid;
|
border: black 1px solid;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@@ -206,7 +240,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.draggable-box {
|
.draggable-box {
|
||||||
cursor: all-scroll;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.properties {
|
.properties {
|
||||||
@@ -232,13 +266,9 @@
|
|||||||
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
position: fixed;
|
||||||
justify-content: center;
|
top: 17vh;
|
||||||
align-items: center;
|
left: 10.5vw;
|
||||||
position: absolute;
|
|
||||||
top: 7.5vh;
|
|
||||||
left: 0.5vw;
|
|
||||||
height: 90vh;
|
|
||||||
}
|
}
|
||||||
.toolbar button {
|
.toolbar button {
|
||||||
margin-top: 10%;
|
margin-top: 10%;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import seatplan from '@/components/seatplan.vue';
|
import seatplan from '@/components/seatplan/userApp/userWindow.vue';
|
||||||
import noseatplan from '@/components/noseatplan.vue';
|
import noseatplan from '@/components/noseatplan.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
Reference in New Issue
Block a user