homemanager-fe/src/views/building/floors/RoomPolygon.vue

75 lines
2.0 KiB
Vue

<template>
<div
v-if="!highlighted || highlighted === room.id"
:class="[
highlighted
? ''
: 'flex cursor-pointer items-center justify-center transition-transform hover:scale-105',
' absolute',
]"
:style="roomPositionCSS"
>
<div
class="pointer-events-auto absolute"
:style="roomPolygonCSS"
@click.stop="clickOnRoom($event)"
@mousemove="moveOverRoom($event)"
></div>
<span class="pointer-events-none z-10" v-if="!highlighted">{{
room.displayName
}}</span>
<slot />
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { RoomLayoutObject } from '../../../interfaces/room.interfaces';
const props = defineProps<{
room: RoomLayoutObject;
zoom: number;
highlighted?: number;
}>();
const emit = defineEmits<{
(e: 'clickedIn', x: number, y: number): void;
(e: 'mouseMovedIn', x: number, y: number): void;
}>();
const mouseCoordsFromEvent = (ev: MouseEvent): [number, number] => {
const rect = (ev.target as HTMLElement).getBoundingClientRect();
return [
(ev.clientX - rect.left) / props.zoom,
(ev.clientY - rect.top) / props.zoom,
];
};
const clickOnRoom = (ev: MouseEvent) =>
emit('clickedIn', ...mouseCoordsFromEvent(ev));
const moveOverRoom = (ev: MouseEvent) =>
emit('mouseMovedIn', ...mouseCoordsFromEvent(ev));
const roomPolygonCSS = computed(() => {
if (!props.room) return {};
const [min, max] = props.room.boundingBox;
return {
clipPath: `polygon(${props.room.plan
.map((point) => `${point[0] - min[0]}px ${point[1] - min[1]}px`)
.join(', ')})`,
width: `${max[0] - min[0]}px`,
height: `${max[1] - min[1]}px`,
backgroundColor: 'rgb(40 180 255 / 40%)',
};
});
const roomPositionCSS = computed(() => {
if (!props.room) return {};
const [min, max] = props.room.boundingBox;
return {
top: `${min[1]}px`,
left: `${min[0]}px`,
width: `${max[0] - min[0]}px`,
height: `${max[1] - min[1]}px`,
};
});
</script>