search_ui/components/entity/components/AiDependency.vue
2025-02-01 14:36:10 +03:30

404 lines
12 KiB
Vue

<template>
<div class="ai-dep">
<div>
<v-chart
:key="renderChart"
class="chart"
:option="option"
@click="handleNodeClick"
@dblclick="handleNodeDblClick"
ref="chart"
lazy
/>
</div>
</div>
</template>
<script>
import { use } from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { GraphChart } from "echarts/charts";
import {
TitleComponent,
TooltipComponent,
LegendComponent,
} from "echarts/components";
// import VChart from "vue-echarts";
import { mapState } from "pinia";
use([
CanvasRenderer,
GraphChart,
TitleComponent,
TooltipComponent,
LegendComponent,
]);
/**
* @vue-data {String} [activeTag=""] - تگ فعال
* @vue-data {Array} [selectedNodes=[]] - نودهای انتخاب شده
* @vue-data {Object|null} [option=null] - گزینه‌های چارت
*/
export default {
props: {
aiDependencyData: {
default: [],
},
},
data() {
return {
activeTag: "",
sentence: "این یک جمله نمونه برای تست است",
selectedNodes: [],
option: {
title: {
textStyle: {
fontFamily: "sahel",
},
text: "ارتباط یابی نحوی کلمات",
},
tooltip: {
textStyle: {
fontFamily: "sahel",
},
},
animationDurationUpdate: 1500,
animationEasingUpdate: "quinticInOut",
series: [
{
type: "graph",
layout: "none",
symbolSize: 50,
roam: false,
symbol: "roundRect",
label: {
show: true,
fontSize: 14,
fontFamily: "sahel",
// formatter: (params) => {
// return nodes[params.dataIndex].name;
// },
},
itemStyle: {
borderColor: "rgb(127, 170, 170)",
borderWidth: 1,
color: "#fff",
borderRadius: [10, 10],
},
edgeSymbol: ["circle", "arrow"],
edgeSymbolSize: [4, 10],
edgeLabel: {
fontFamily: "sahel",
fontSize: 18,
show: true,
formatter: (params) => {
return ` ${params.data.edgeLabel.formatter}{cross|}`; // استفاده از متن ذخیره شده برای هر لینک
},
rich: {
cross: {
align: "right",
verticalAlign: "top",
// backgroundColor: {
// image:
// "data:image/svg+xml;utf8," + encodeURIComponent(crossSvg),
// },
color: "#f3f3f3",
height: 15,
width: 15,
},
},
// color:'#ddd',
backgroundColor: "#f3f3f3",
padding: [8, 8],
borderRadius: [5, 5],
},
data: this.aiDependencyData,
links: [],
lineStyle: {
opacity: 0.9,
width: 2,
curveness: 0,
},
},
],
},
entity: undefined,
renderChart: 1,
};
},
watch: {
aiDependencyData(newVal) {
// this.option = this.generateOption();
this.generateOption();
},
},
computed: {
...mapState("aiTools", ["aiToolsActiveActionGetter"]),
repoUrl() {
return import.meta.env.VITE_REPO + "/";
},
},
mounted() {
// تولید تنظیمات اولیه نمودار در زمان مونت شدن کامپوننت
// this.option = this.generateOption();
// this.activeTag = this.aiToolsActiveActionGetter?.tags[0];
this.generateOption()
},
methods: {
setEntity(entity) {
this.entity = entity;
this.renderByEntity(entity);
},
renderByEntity(entity) {
this.aiResults = [];
this.sectionText = "";
this.result_token = [];
this.result_objects = {};
if (!entity) return;
},
/**
* تولید گزینه‌های نمودار.
* این متد جمله را به کلمات تقسیم کرده و هر کلمه را به عنوان یک نود در نمودار قرار می‌دهد.
*
* @returns {object} - گزینه‌های نمودار برای نمایش ارتباط بین کلمات
*/
generateOption() {
let allLinks = [];
this.aiDependencyData.forEach((element, index) => {
element["name"] = element["form"];
element["x"] = 5 + index * 5;
element["y"] = 100;
element["itemStyle"] = {
borderColor: "rgb(127, 170, 170)",
borderWidth: 1,
color: "#fff",
borderRadius: [10, 10],
};
let elementLinks = this.generateLinks(this.aiDependencyData);
allLinks.push(...elementLinks);
});
this.option.series[0].data = this.aiDependencyData;
this.option.series[0].links = allLinks;
this.renderChart++;
},
generateLinks(data) {
let links = [];
data.forEach((node) => {
if (node.head !== 0) {
// پیدا کردن نود هدف (target)
const targetNode = data.find((n) => n.id === node.head);
// console.log("🚀 ~ data.forEach ~ node.head:", node.head)
// console.log("🚀 ~ data.forEach ~ targetNode:", targetNode)
// اضافه کردن لینک به لیست
links.push({
source: node.id, // نام نود فعلی
target: targetNode.id, // نام نود هدف
label: {
show: true,
},
lineStyle: {
curveness: 1,
width: 3,
color: "#da89d0",
},
edgeLabel: {
show: true,
formatter: node.deprel, // استفاده از رابطه وابستگی به عنوان متن برچسب
fontSize: 20,
},
});
}
});
// console.log("🚀 ~ generateLinks ~ links:", links)
return links;
},
/**
* مدیریت کلیک بر روی نودها در نمودار.
* این متد به طور خاص برای حذف لینک‌ها (فلش‌ها) و تغییر رنگ مد های مربوط به فلش‌ها طراحی شده است.
*
* @param {object} params - پارامترهای رویداد کلیک بر روی نود
*/
handleNodeClick(params) {
const clickedNode = params.data;
// بررسی اینکه آیا بر روی یک لینک (فلش) کلیک شده است یا نه
if (params.dataType === "edge") {
// حذف لینک (فلش) از نمودار
this.option.series[0].links = this.option.series[0].links.filter(
(link) => {
return !(
link.source === clickedNode.source &&
link.target === clickedNode.target
);
}
);
this.option.series[0].data.forEach((node) => {
if (
node.id === clickedNode.source ||
node.id === clickedNode.target
) {
node.itemStyle.color = "#fff";
node.color = "#fff";
}
});
this.$refs.chart.setOption(this.option);
return;
}
// ادامه منطق کلیک بر روی نودها
this.option.series[0].data.forEach((node) => {
if (node.id === clickedNode.id) {
if (node.itemStyle.color === "#ddd") {
// بررسی رنگ قبلی و تنظیم رنگ فعلی بر اساس آن
if (node.previousColor === "#fff") {
node.itemStyle.color = "#fff";
} else if (node.previousColor === this.activeTag.color) {
node.itemStyle.color = this.activeTag.color;
}
this.selectedNodes = this.selectedNodes.filter(
(id) => id !== clickedNode.id
);
} else {
// ذخیره رنگ فعلی به عنوان رنگ قبلی و سپس تغییر رنگ به #ddd
node.previousColor = node.itemStyle.color;
node.itemStyle.color = "#ddd";
if (!this.selectedNodes.includes(clickedNode.id)) {
this.selectedNodes.push(clickedNode.id);
}
}
}
});
// اگر دو نود انتخاب شده باشد، لینکی بین آنها ایجاد می‌شود
if (this.selectedNodes.length === 2) {
const [sourceId, targetId] = this.selectedNodes;
const existingLink = this.option.series[0].links.find(
(link) =>
(link.source === sourceId && link.target === targetId) ||
(link.source === targetId && link.target === sourceId)
);
if (!existingLink) {
const linkColor = this.activeTag.color;
// تغییر رنگ نودهای انتخاب شده
this.option.series[0].data.forEach((node) => {
if (node.id === sourceId || node.id === targetId) {
node.itemStyle.color = linkColor;
node.color = linkColor;
}
});
// اضافه کردن لینک جدید بین دو نود
this.option.series[0].links.push({
source: sourceId,
target: targetId,
label: { show: true },
lineStyle: { curveness: 1, width: 3, color: linkColor },
edgeLabel: {
show: true,
formatter: this.activeTag.label,
fontSize: 20,
},
});
this.selectedNodes = [];
}
}
// به روزرسانی نمودار
this.$refs.chart.setOption(this.option);
},
/**
* مدیریت دابل کلیک بر روی نودها در نمودار.
* این متد یک خط جدید بالای نود کلیک شده اضافه می‌کند.
*
* @param {object} params - پارامترهای رویداد دابل کلیک بر روی نود
*/
handleNodeDblClick(params) {
const clickedNode = params.data; // استفاده از params.data برای دسترسی به داده‌های نود کلیک شده
// اضافه کردن یک خط جدید بالای نود کلیک شده
this.option.series[0].links.push({
source: clickedNode.id,
target: {
x: clickedNode.x,
y: clickedNode.y - 50, // تنظیم مکان خط بالای نود
name: this.activeTag.label,
itemStyle: {
color: "transparent", // مخفی کردن نود مقصد
},
label: {
show: true,
position: "top",
formatter: this.activeTag.label, // متن دلخواه
fontSize: 16,
fontFamily: "sahel",
},
},
lineStyle: {
curveness: 0,
width: 2,
color: this.activeTag.color,
},
});
this.$refs.chart.setOption(this.option); // به‌روزرسانی نمودار با تغییرات اعمال شده
},
/**
* تنظیم برچسب فعال.
* این متد برچسب فعال را تنظیم می‌کند که برای لینک‌ها استفاده می‌شود.
*
* @param {object} activeTag - برچسب فعال شامل نام و رنگ
*/
setActiveTag(activeTag) {
// اگر فلش انتخاب شده بود، آن را حذف کنید
if (activeTag.key === "flash") {
// پیدا کردن فلش در تگ‌ها
const flashTag = this.aiToolsActiveActionGetter.tags.find(
(tag) => tag.key === "flash"
);
// اگر فلش موجود بود، حذف کنید
if (flashTag) {
const index = this.aiToolsActiveActionGetter.tags.indexOf(flashTag);
this.aiToolsActiveActionGetter.tags.splice(index, 1);
}
}
// تنظیم برچسب فعال
this.activeTag = activeTag;
// اگر فلش انتخاب شده بود، تغییر رنگ مد های مربوطه
if (activeTag.key === "flash") {
this.option.series[0].data.forEach((node) => {
if (node.name.includes("flash")) {
node.itemStyle.color = activeTag.color;
}
});
}
},
},
};
</script>
<style scoped>
.chart {
height: 850px;
width: 800px;
align-items: center;
}
</style>