knxdisplay/web-interface/src/components/widgets/elements/ChartElement.vue
2026-02-04 21:11:04 +01:00

70 lines
2.6 KiB
Vue

<template>
<div
class="z-[1] select-none touch-none"
:class="selected ? 'outline outline-2 outline-accent outline-offset-2' : ''"
:style="computedStyle"
@mousedown.stop="$emit('drag-start', { id: widget.id, event: $event })"
@touchstart.stop="$emit('drag-start', { id: widget.id, event: $event })"
@click.stop="$emit('select')"
>
<div class="w-full h-full flex flex-col gap-2">
<div class="text-[11px] uppercase tracking-[0.12em] opacity-80">
{{ widget.text || 'Chart' }}
</div>
<div class="flex-1 rounded-[10px] bg-black/20 relative overflow-hidden">
<div class="absolute inset-0 opacity-30" style="background-image: linear-gradient(to right, rgba(255,255,255,0.1) 1px, transparent 1px), linear-gradient(to bottom, rgba(255,255,255,0.1) 1px, transparent 1px); background-size: 24px 24px;"></div>
<svg class="absolute inset-0" viewBox="0 0 100 40" preserveAspectRatio="none">
<path d="M0,30 L15,22 L30,26 L45,14 L60,18 L75,10 L100,16" fill="none" stroke="rgba(239,99,81,0.8)" stroke-width="2" />
<path d="M0,34 L20,28 L40,32 L60,20 L80,24 L100,18" fill="none" stroke="rgba(125,211,176,0.8)" stroke-width="2" />
</svg>
</div>
</div>
<!-- Resize Handle -->
<div
v-if="selected"
class="absolute -right-1.5 -bottom-1.5 w-3.5 h-3.5 rounded-[4px] bg-accent border-[2px] border-[#1b1308] shadow-[0_4px_12px_rgba(0,0,0,0.35)] cursor-se-resize z-10"
data-resize-handle
@mousedown.stop="$emit('resize-start', { id: widget.id, event: $event })"
@touchstart.stop="$emit('resize-start', { id: widget.id, event: $event })"
>
<span class="absolute right-[2px] bottom-[2px] w-[6px] h-[6px] border-r-2 border-b-2 border-[#1b1308a6] rounded-[2px]"></span>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue';
import { getBaseStyle, clamp, hexToRgba, getBorderStyle } from '../shared/utils';
const props = defineProps({
widget: { type: Object, required: true },
scale: { type: Number, default: 1 },
selected: { type: Boolean, default: false }
});
defineEmits(['select', 'drag-start', 'resize-start']);
const computedStyle = computed(() => {
const w = props.widget;
const s = props.scale;
const style = getBaseStyle(w, s);
if (w.bgOpacity > 0) {
const alpha = clamp(w.bgOpacity / 255, 0, 1).toFixed(2);
style.background = hexToRgba(w.bgColor, alpha);
}
if (w.radius > 0) {
style.borderRadius = `${w.radius * s}px`;
}
Object.assign(style, getBorderStyle(w, s));
style.padding = `${12 * s}px`;
return style;
});
</script>