|
@@ -1,6 +1,10 @@
|
|
|
<template>
|
|
<template>
|
|
|
<!-- 全 Canvas 关系图谱 - Force-directed 物理布局 -->
|
|
<!-- 全 Canvas 关系图谱 - Force-directed 物理布局 -->
|
|
|
<view class="family-graph-wrapper" v-if="simNodes && simNodes.length >= 1">
|
|
<view class="family-graph-wrapper" v-if="simNodes && simNodes.length >= 1">
|
|
|
|
|
+ <!-- 右上角小齿轮 -->
|
|
|
|
|
+ <view class="gear-icon" @click="onManageTap">
|
|
|
|
|
+ <text class="gear-text">⚙</text>
|
|
|
|
|
+ </view>
|
|
|
<canvas
|
|
<canvas
|
|
|
class="family-graph-canvas"
|
|
class="family-graph-canvas"
|
|
|
canvas-id="forceGraphCanvas"
|
|
canvas-id="forceGraphCanvas"
|
|
@@ -9,7 +13,19 @@
|
|
|
:style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"
|
|
:style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"
|
|
|
@touchstart="onTouchStart"
|
|
@touchstart="onTouchStart"
|
|
|
@touchmove="onTouchMove"
|
|
@touchmove="onTouchMove"
|
|
|
- @touchend="onTouchEnd" />
|
|
|
|
|
|
|
+ @touchend="onTouchEnd"
|
|
|
|
|
+ @click="onCanvasClick" />
|
|
|
|
|
+ <!-- PC 端悬停检测层 -->
|
|
|
|
|
+ <view
|
|
|
|
|
+ v-if="isPC"
|
|
|
|
|
+ class="hover-layer"
|
|
|
|
|
+ :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"
|
|
|
|
|
+ @mousemove="onHoverMove"
|
|
|
|
|
+ @mouseleave="onHoverLeave" />
|
|
|
|
|
+ <!-- + 添加成员提示(触摸/悬停时显示在中心节点旁) -->
|
|
|
|
|
+ <view class="add-hint" :class="{ 'add-hint-visible': touchingSelf || hoveringSelf }" :style="addHintPosition">
|
|
|
|
|
+ <text class="add-hint-text">+</text>
|
|
|
|
|
+ </view>
|
|
|
</view>
|
|
</view>
|
|
|
<!-- 空状态 -->
|
|
<!-- 空状态 -->
|
|
|
<view class="family-graph-empty" v-else-if="members && members.length === 0">
|
|
<view class="family-graph-empty" v-else-if="members && members.length === 0">
|
|
@@ -93,6 +109,13 @@ export default {
|
|
|
animFrameId: null,
|
|
animFrameId: null,
|
|
|
isSimulating: false,
|
|
isSimulating: false,
|
|
|
|
|
|
|
|
|
|
+ // 触摸/悬停状态(显示 + 号)
|
|
|
|
|
+ touchingSelf: false,
|
|
|
|
|
+ hoveringSelf: false,
|
|
|
|
|
+
|
|
|
|
|
+ // 是否 PC 环境(h5 编译)
|
|
|
|
|
+ isPC: false,
|
|
|
|
|
+
|
|
|
// 主题色
|
|
// 主题色
|
|
|
themeColors: {
|
|
themeColors: {
|
|
|
body: '#8D6E63',
|
|
body: '#8D6E63',
|
|
@@ -108,6 +131,16 @@ export default {
|
|
|
return this.themeColors[this.dimensionCode] || '#8D6E63'
|
|
return this.themeColors[this.dimensionCode] || '#8D6E63'
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
|
|
+ // + 提示位置(跟随中心节点偏移)
|
|
|
|
|
+ addHintPosition: function() {
|
|
|
|
|
+ var selfNode = this.simNodes.find(function(n) { return n.isSelf })
|
|
|
|
|
+ if (!selfNode) return {}
|
|
|
|
|
+ return {
|
|
|
|
|
+ left: (selfNode.x + selfNode.radius * 0.7) + 'px',
|
|
|
|
|
+ top: (selfNode.y - selfNode.radius * 0.5) + 'px'
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
// 将 members 转换为 simNodes
|
|
// 将 members 转换为 simNodes
|
|
|
nodeData: function() {
|
|
nodeData: function() {
|
|
|
var self = this
|
|
var self = this
|