Files
momentry_portal/src/components/TraceSimilarityMatrix.vue
2026-05-20 08:29:37 +08:00

64 lines
2.3 KiB
Vue

<template>
<div class="space-y-2">
<div class="flex items-center justify-between">
<h3 class="text-sm font-semibold text-gray-300">相似度矩陣 V4</h3>
<span class="text-xs text-gray-500">{{ traces.length }} traces</span>
</div>
<div class="bg-gray-900 rounded p-4 overflow-x-auto" v-if="matrix.length">
<svg :width="cellS * matrix.length + 60" :height="cellS * matrix.length + 40" class="block">
<!-- labels -->
<text v-for="(_, i) in matrix" :key="'l'+i"
:x="cellS * i + cellS / 2 + 50" :y="14" fill="#9ca3af" font-size="7" text-anchor="end"
transform="rotate(-60, 10, 10)">{{ traces[i]?.trace_id }}</text>
<text v-for="(_, i) in matrix" :key="'r'+i"
:x="44" :y="cellS * i + cellS / 2 + 24" fill="#9ca3af" font-size="7">{{ traces[i]?.trace_id }}</text>
<!-- cells -->
<g v-for="(row, i) in matrix" :key="i">
<rect v-for="(v, j) in row" :key="j"
:x="cellS * j + 50" :y="cellS * i + 20"
:width="cellS" :height="cellS"
:fill="color(v)" stroke="#374151" stroke-width="0.5" />
</g>
</svg>
</div>
<div v-else class="text-center text-gray-500 text-sm py-8">no data</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
const props = defineProps<{ traces: any[] }>()
const cellS = 14
const maxN = 40
const matrix = computed(() => {
const t = props.traces.slice(0, maxN)
if (t.length < 2) return []
const durs = t.map(x => x.duration_sec || 0)
const cnt = t.map(x => x.face_count || 0)
const maxDur = Math.max(...durs, 1)
const maxCnt = Math.max(...cnt, 1)
const m: number[][] = []
for (let i = 0; i < t.length; i++) {
const row: number[] = []
for (let j = 0; j < t.length; j++) {
if (i === j) { row.push(1); continue }
// Simple similarity: duration + face_count proximity
const durSim = 1 - Math.abs(durs[i] - durs[j]) / maxDur
const cntSim = 1 - Math.abs(cnt[i] - cnt[j]) / maxCnt
row.push((durSim + cntSim) / 2)
}
m.push(row)
}
return m
})
function color(v: number): string {
if (v > 0.85) return 'rgba(68, 255, 68, 0.8)' // bright green = similar
if (v > 0.7) return 'rgba(68, 200, 68, 0.6)'
if (v > 0.5) return 'rgba(100, 100, 100, 0.4)'
return 'rgba(40, 40, 50, 0.3)' // dark = dissimilar
}
</script>