121 lines
3.5 KiB
Vue
121 lines
3.5 KiB
Vue
<template>
|
|
<Teleport to="body">
|
|
<Modal v-if="isModalOpen" :isModalOpen="true" :closable="false" :modal-width="745" :modal-height="460">
|
|
<template #modalHeader>
|
|
<h3 class="modal-title">Decorations</h3>
|
|
</template>
|
|
<template #modalBody>
|
|
<div class="container decorations">
|
|
<div class="buttons">
|
|
<button class="btn-cyan" @click="zoneEditorStore.setDrawMode('tile')">Walls</button>
|
|
<button class="btn-cyan" @click="zoneEditorStore.setDrawMode('tile')">Decorations</button>
|
|
<button class="btn-cyan" @click="zoneEditorStore.setDrawMode('tile')">NPC</button>
|
|
</div>
|
|
<canvas ref="canvas" :width="decorationWidth" :height="decorationHeight" style="display: none"></canvas>
|
|
<div class="decorations">
|
|
<img v-for="(decoration, index) in decorations" :key="index" :src="decoration" alt="Decoration" @click="zoneEditorStore.setSelectedDecoration(index)" :class="{ selected: zoneEditorStore.selectedDecoration && zoneEditorStore.selectedDecoration === index }" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</Modal>
|
|
</Teleport>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, onMounted, nextTick } from 'vue'
|
|
import config from '@/config'
|
|
import Modal from '@/components/utilities/Modal.vue'
|
|
import { useZoneEditorStore } from '@/stores/zoneEditor'
|
|
|
|
const decorationWidth = config.wall_size.x
|
|
const decorationHeight = config.wall_size.y
|
|
const decorations = ref<number[][]>([])
|
|
const selectedDecoration = ref<number | null>(null)
|
|
const canvas = ref<HTMLCanvasElement | null>(null)
|
|
const isModalOpen = ref(false)
|
|
const zoneEditorStore = useZoneEditorStore()
|
|
|
|
// Hardcoded image path
|
|
const imagePath = '/assets/zone/walls.png'
|
|
|
|
const loadImage = (src: string): Promise<HTMLImageElement> => {
|
|
return new Promise((resolve) => {
|
|
const img = new Image()
|
|
img.onload = () => resolve(img)
|
|
img.src = src
|
|
})
|
|
}
|
|
|
|
const splitDecorations = (img: HTMLImageElement) => {
|
|
if (!canvas.value) {
|
|
console.error('Canvas not found')
|
|
return
|
|
}
|
|
const ctx = canvas.value.getContext('2d')
|
|
if (!ctx) {
|
|
console.error('Failed to get canvas context')
|
|
return
|
|
}
|
|
|
|
const decorationsetWidth = img.width
|
|
const decorationsetHeight = img.height
|
|
const columns = Math.floor(decorationsetWidth / decorationWidth)
|
|
const rows = Math.floor(decorationsetHeight / decorationHeight)
|
|
|
|
decorations.value = []
|
|
selectedDecoration.value = null
|
|
|
|
for (let row = 0; row < rows; row++) {
|
|
for (let col = 0; col < columns; col++) {
|
|
const x = col * decorationWidth
|
|
const y = row * decorationHeight
|
|
|
|
ctx.clearRect(0, 0, decorationWidth, decorationHeight)
|
|
ctx.drawImage(img, x, y, decorationWidth, decorationHeight, 0, 0, decorationWidth, decorationHeight)
|
|
|
|
const decorationDataURL = canvas.value.toDataURL()
|
|
decorations.value.push(decorationDataURL)
|
|
}
|
|
}
|
|
}
|
|
|
|
const selectDecoration = (index: number) => {
|
|
selectedDecoration.value = index
|
|
}
|
|
|
|
onMounted(async () => {
|
|
isModalOpen.value = true
|
|
const img = await loadImage(imagePath)
|
|
await nextTick()
|
|
splitDecorations(img)
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
@import '@/assets/scss/main';
|
|
|
|
.decorations {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
}
|
|
|
|
.decorations img {
|
|
width: 30px;
|
|
height: 130px;
|
|
cursor: pointer;
|
|
border: 2px solid transparent;
|
|
transition: border 0.3s ease;
|
|
}
|
|
|
|
.buttons {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
}
|
|
|
|
.decorations img.selected {
|
|
border: 2px solid $red;
|
|
}
|
|
</style>
|