404 lines
12 KiB
Vue
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>
|