248 lines
6.5 KiB
Vue
248 lines
6.5 KiB
Vue
<template>
|
|
<div id="sidebar-container">
|
|
<div class="sidebar-section">
|
|
<div>
|
|
<input type="file" id="file" @change="loadImage($event)">
|
|
</div>
|
|
<div class="section-formlike">
|
|
<label>Image size:</label>
|
|
<div class="readout">{{imageSize[0]}} x {{imageSize[1]}}</div>
|
|
</div>
|
|
</div>
|
|
<div class="sidebar-section">
|
|
<div class="section-formlike">
|
|
<label for="slice_x">Slice X: </label>
|
|
<input class="spinBox" id="slice_x" v-model.number="guideSizeX" type="number"
|
|
min="2" :max="imageSize[0]/2" step="1" value="64">
|
|
</div>
|
|
<div>
|
|
<label for="slice_x">X remainder: {{this.imageSize[0] % this.guideSizeX}}</label>
|
|
</div>
|
|
<div class="section-formlike">
|
|
<label for="slice_y">Slice Y: </label>
|
|
<input class="spinBox" id="slice_y" v-model.number="guideSizeY" type="number"
|
|
min="2" :max="imageSize[1]/2" step="1" value="64">
|
|
</div>
|
|
<div>
|
|
<label for="slice_x">Y remainder: {{this.imageSize[1] % this.guideSizeY}}</label>
|
|
</div>
|
|
<div class="section-formlike">
|
|
<label for="lockSize">Maintain square ratio: </label>
|
|
<input type="checkbox" id="lockSize" v-model="lockSize">
|
|
</div>
|
|
<div class="section-formlike">
|
|
<label for="cleanSize">Allow only clean sizes: </label>
|
|
<input type="checkbox" id="cleanSize" v-model="cleanSize">
|
|
</div>
|
|
</div>
|
|
<div class="sidebar-section">
|
|
<div class="section-formlike">
|
|
<label>Offset: x={{offset[0]}}, y={{offset[1]}}</label>
|
|
<button @click="$emit('params', {type: 'offset', x: 0, y: 0})">RESET</button>
|
|
</div>
|
|
</div>
|
|
<div class="sidebar-section">
|
|
<div class="section-formlike">
|
|
<label>Total amount of slices:</label>
|
|
<div class="readout">{{slices}}</div>
|
|
</div>
|
|
<div class="section-formlike">
|
|
<label for="fps">FPS: </label>
|
|
<input class="spinBox" id="fps" v-model="fps" type="number" min="1" max="60" step="1" value="60" disabled>
|
|
</div>
|
|
<div class="section-formlike">
|
|
<label>Est. length:</label>
|
|
<div class="readout">{{length}}</div>
|
|
</div>
|
|
</div>
|
|
<div class="sidebar-section player-section">
|
|
<player class="player" :width="guideSizeX" :height="guideSizeY" :offset="offset" @frames="(n)=>{slices=n}"/>
|
|
</div>
|
|
<div class="footer"><a :href="env.HOMEPAGE_URL">Version: {{env.VERSION}}</a></div>
|
|
</div>
|
|
</template>
|
|
|
|
<!--suppress JSSuspiciousNameCombination -->
|
|
<script>
|
|
import Player from "@/components/Player";
|
|
|
|
export default {
|
|
name: "Sidebar",
|
|
components: {
|
|
player: Player,
|
|
},
|
|
props: ["slice", "offset"],
|
|
data: function () {
|
|
return {
|
|
imageSize: [-1, -1],
|
|
guideSizeX: 64,
|
|
guideSizeY: 64,
|
|
lastGuideSizeX: 64,
|
|
lastGuideSizeY: 64,
|
|
lockSize: true,
|
|
cleanSize: false,
|
|
slices: 0,
|
|
fps: 60,
|
|
};
|
|
},
|
|
watch: {
|
|
guideSizeX (size) {
|
|
if (this.lockSize) this.guideSizeY = size;
|
|
if (this.cleanSize) {
|
|
let tmpSize = parseInt(size);
|
|
while (this.imageSize[0] % tmpSize !== 0 &&
|
|
tmpSize < this.imageSize[0] &&
|
|
tmpSize > 2) {
|
|
if (this.lastGuideSizeX < size) {
|
|
tmpSize += 1;
|
|
} else {
|
|
tmpSize -= 1;
|
|
}
|
|
}
|
|
if (tmpSize !== 2 && tmpSize !== this.imageSize[0]) {
|
|
this.guideSizeX = tmpSize;
|
|
}
|
|
}
|
|
this.$emit("params", {
|
|
type: "slice",
|
|
x: this.guideSizeX,
|
|
y: this.guideSizeY,
|
|
});
|
|
this.lastGuideSizeX = this.guideSizeX;
|
|
this.lastGuideSizeY = this.guideSizeY;
|
|
},
|
|
guideSizeY (size) {
|
|
if (this.lockSize) this.guideSizeX = size;
|
|
if (this.cleanSize) {
|
|
let tmpSize = parseInt(size);
|
|
while (this.imageSize[1] % tmpSize !== 0 &&
|
|
tmpSize < this.imageSize[1] &&
|
|
tmpSize > 2) {
|
|
if (this.lastGuideSizeY < size) {
|
|
tmpSize += 1;
|
|
} else {
|
|
tmpSize -= 1;
|
|
}
|
|
}
|
|
if (tmpSize !== 2 && tmpSize !== this.imageSize[1]) {
|
|
this.guideSizeY = tmpSize;
|
|
}
|
|
}
|
|
this.$emit("params", {
|
|
type: "slice",
|
|
x: this.guideSizeX,
|
|
y: this.guideSizeY,
|
|
});
|
|
this.lastGuideSizeX = this.guideSizeX;
|
|
this.lastGuideSizeY = this.guideSizeY;
|
|
},
|
|
slice: function (size) {
|
|
this.lockSize = size[0] === size[1];
|
|
this.guideSizeX = size[0];
|
|
this.guideSizeY = size[1];
|
|
},
|
|
lockSize: function (locked) {
|
|
if (locked) {
|
|
if (this.guideSizeX < this.guideSizeY) {
|
|
this.guideSizeY = this.guideSizeX;
|
|
} else {
|
|
this.guideSizeX = this.guideSizeY;
|
|
}
|
|
this.cleanSize = false;
|
|
}
|
|
},
|
|
cleanSize: function (clean) {
|
|
if (clean) {
|
|
this.lockSize = false;
|
|
}
|
|
},
|
|
},
|
|
computed: {
|
|
length: function () {
|
|
if (this.imageSize[0] === -1 || this.imageSize[1] === -1) {
|
|
return "-";
|
|
} else {
|
|
let seconds = Math.round(this.slices / this.fps * 100) / 100;
|
|
|
|
let mins = Math.floor(seconds / 60);
|
|
let secs = Math.round(seconds % 60);
|
|
|
|
return "~" + seconds + " seconds" + (mins > 0 ? (" (" + mins + "m " + secs + "s)") : "");
|
|
}
|
|
},
|
|
env: function () {
|
|
// eslint-disable-next-line no-undef
|
|
return process.env;
|
|
},
|
|
},
|
|
methods: {
|
|
loadImage (e) {
|
|
let url = URL.createObjectURL(e.target.files[0]);
|
|
this.$emit("loadImage", url);
|
|
},
|
|
setParams (coords) {
|
|
switch (coords.type) {
|
|
case "size":
|
|
this.lockSize = false;
|
|
this.guideSizeX = coords.x;
|
|
this.guideSizeY = coords.y;
|
|
break;
|
|
}
|
|
},
|
|
},
|
|
mounted: function () {
|
|
this.$bus.$on("imageLoaded", (image) => {
|
|
this.imageSize = [image.width, image.height];
|
|
});
|
|
this.$emit("guideSize", [this.guideSizeX, this.guideSizeY]);
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
#sidebar-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
height: 100%;
|
|
|
|
border-right: 1px solid black;
|
|
}
|
|
|
|
.sidebar-section {
|
|
padding: .5em;
|
|
border-bottom: 1px solid grey;
|
|
}
|
|
|
|
.sidebar-section > div {
|
|
padding: .25em;
|
|
}
|
|
|
|
.section-formlike {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.section-formlike input[type="number"] {
|
|
width: 4em;
|
|
text-align: center;
|
|
}
|
|
|
|
.section-formlike .readout {
|
|
min-width: 4em;
|
|
text-align: center;
|
|
}
|
|
|
|
.player-section {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.footer {
|
|
position: absolute;
|
|
bottom: .5em;
|
|
left: .5em;
|
|
}
|
|
</style>
|