实现连接线的动画
This commit is contained in:
parent
f36fd94cbb
commit
3e2c7e3ae0
@ -16,9 +16,11 @@
|
||||
--instance-color: #CB81DA;
|
||||
--instance-fill-color: rgba(203, 129, 218, 0.1);
|
||||
--wire-color: var(--foreground);
|
||||
--wire-active-color: #CB81DA;
|
||||
--wire-ball-color: #CB81DA;
|
||||
--cross-dot-color: var(--foreground);
|
||||
--port-color: rgb(70, 70, 222);
|
||||
--port-fill-color: rgba(70, 70, 222, 0.1);
|
||||
--port-fill-color: rgba(70, 70, 222, 0.25);
|
||||
|
||||
/* css 动画属性 */
|
||||
--animation-7s: .7s cubic-bezier(0.23,1,0.32,1);
|
||||
|
@ -53,4 +53,9 @@ onMounted(async () => {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.connection-line {
|
||||
cursor: pointer;
|
||||
transition: var(--animation-5s);
|
||||
}
|
||||
|
||||
</style>
|
@ -31,6 +31,12 @@ export const colorManager = reactive({
|
||||
type: 'cross-dot',
|
||||
label: t('cross-dot'),
|
||||
color: 'white'
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
type: 'wire-active',
|
||||
label: t('common.selected-wire'),
|
||||
color: 'white'
|
||||
}
|
||||
],
|
||||
|
||||
|
@ -37,7 +37,9 @@ export class NetlistRender {
|
||||
// 指定 layered 算法的方向为从左到右
|
||||
'elk.direction': 'RIGHT',
|
||||
// 激活 node 分区功能,可以通过 partitioning.partition 赋予 id 的方式给 node 进行分组
|
||||
'elk.partitioning.activate': true
|
||||
'elk.partitioning.activate': true,
|
||||
// 边之间的距离
|
||||
'elk.spacing.edgeEdge': 25
|
||||
}
|
||||
/**
|
||||
* @type {ElkGraph}
|
||||
@ -217,10 +219,10 @@ export class NetlistRender {
|
||||
// 根据最大最小尺寸微调全局方位
|
||||
this.adjustLocation(g);
|
||||
|
||||
setTimeout(() => {
|
||||
// 生成各个 manager 的拖拽上下文
|
||||
this.createManagerDragContext(computedLayout);
|
||||
}, 1000);
|
||||
// setTimeout(() => {
|
||||
// // 生成各个 manager 的拖拽上下文
|
||||
// this.createManagerDragContext(computedLayout);
|
||||
// }, 1000);
|
||||
|
||||
return svg;
|
||||
}
|
||||
@ -276,7 +278,7 @@ export class NetlistRender {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 绘制连线
|
||||
* @description 绘制连线和交叉点
|
||||
* @param {d3.Selection} parentSelection
|
||||
* @param {ElkNode} computedLayout
|
||||
*/
|
||||
@ -581,7 +583,7 @@ export class NetlistRender {
|
||||
const instanceName = elkNode.name;
|
||||
const parentModule = this.nameToModule.get(parentName);
|
||||
const cell = parentModule.view.nameToCell.get(instanceName);
|
||||
|
||||
|
||||
// 先记录当前这个选择集的位置
|
||||
const originX = elkNode.x;
|
||||
const originY = elkNode.y;
|
||||
|
@ -66,9 +66,6 @@ export class PortRender {
|
||||
.attr('dominant-baseline', 'middle') // 文本垂直居中
|
||||
.attr('text-anchor', 'middle') // 文本水平居中
|
||||
.attr('fill', 'var(--foreground)') // 文本颜色
|
||||
.attr('font-size', '0')
|
||||
.transition()
|
||||
.duration(1000)
|
||||
.attr('font-size', '12px')
|
||||
.attr('class', 'port-caption')
|
||||
.text(data => data.text); // 设置文本内容
|
||||
|
@ -1,6 +1,9 @@
|
||||
/* eslint-disable */
|
||||
|
||||
import * as d3 from 'd3';
|
||||
import { globalSetting } from '../global';
|
||||
import { NetlistRender } from '.';
|
||||
import { LINE_WIDTH } from './layout';
|
||||
|
||||
export class WireRender {
|
||||
/**
|
||||
@ -30,16 +33,21 @@ export class WireRender {
|
||||
* @param {ElkEdge} edge
|
||||
*/
|
||||
addAsD3DataItems(points, edge) {
|
||||
for (let i = 0; i < points.length - 1; ++ i) {
|
||||
this.data.push({
|
||||
id: edge.id,
|
||||
x1: points[i].x,
|
||||
y1: points[i].y,
|
||||
x2: points[i + 1].x,
|
||||
y2: points[i + 1].y,
|
||||
strokeWidth: 2
|
||||
});
|
||||
const linePaths = [];
|
||||
for (let i = 0; i < points.length; ++ i) {
|
||||
// 根据点的信息创建 path
|
||||
const command = i === 0 ? 'M': 'L';
|
||||
const x = points[i].x;
|
||||
const y = points[i].y;
|
||||
linePaths.push(`${command}${x},${y}`);
|
||||
}
|
||||
|
||||
const lineSvg = linePaths.join(' ');
|
||||
|
||||
this.data.push({
|
||||
svg: lineSvg,
|
||||
active: false
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -47,16 +55,102 @@ export class WireRender {
|
||||
const id2manager = this.id2manager;
|
||||
const _this = this;
|
||||
|
||||
let lineSelections = this.selection.selectAll('line')
|
||||
|
||||
// 一个 g.lines 管理一个线段
|
||||
let lineSelections = this.selection.selectAll('path.lines')
|
||||
.data(data)
|
||||
.enter()
|
||||
.append('line')
|
||||
.attr('x1', data => data.x1)
|
||||
.attr('y1', data => data.y1)
|
||||
.attr('x2', data => data.x2)
|
||||
.attr('y2', data => data.y2)
|
||||
.append('path')
|
||||
.attr('d', d => d.svg)
|
||||
.attr('class', 'connection-line')
|
||||
.attr("fill", "none")
|
||||
.attr('stroke', 'var(--wire-color)');
|
||||
|
||||
|
||||
const id2animation = new Map();
|
||||
|
||||
lineSelections.on('click', function(_, data) {
|
||||
data.active = !data.active;
|
||||
|
||||
if (data.active) {
|
||||
const pathSelection = d3.select(this);
|
||||
// 如果当前激活,显示数据流向
|
||||
const pathLength = pathSelection.node().getTotalLength();
|
||||
|
||||
const pivot = _this.selection
|
||||
.append('circle')
|
||||
.attr('r', 6)
|
||||
.attr('fill', 'var(--wire-ball-color)');
|
||||
|
||||
// 进行一次动画
|
||||
function renderOneAnimation() {
|
||||
console.log(pathLength);
|
||||
// 1400 的长度差不多配 3500 ?
|
||||
const duration = pathLength / 14 * 35;
|
||||
let transition = pivot.transition().duration(duration);
|
||||
transition.attrTween('transform', () => {
|
||||
return t => {
|
||||
const x = cubicBezierAnimation(t, 0, pathLength);
|
||||
const point = pathSelection.node().getPointAtLength(x);
|
||||
return `translate(${point.x},${point.y})`;
|
||||
}
|
||||
});
|
||||
transition = transition.on('end', renderOneAnimation);
|
||||
// 动画结束后重新启动动画
|
||||
id2animation.set(data.id, {
|
||||
pivot,
|
||||
transition
|
||||
});
|
||||
}
|
||||
|
||||
renderOneAnimation();
|
||||
} else {
|
||||
if (id2animation.has(data.id)) {
|
||||
const { pivot, transition } = id2animation.get(data.id);
|
||||
pivot.remove();
|
||||
id2animation.delete(data.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
lineSelections.on('mouseenter', function(_, data) {
|
||||
const selection = d3.select(this);
|
||||
// 移动到最上层
|
||||
selection.raise();
|
||||
selection.attr('stroke', 'var(--wire-active-color)');
|
||||
});
|
||||
|
||||
lineSelections.on('mouseleave', function(_, data) {
|
||||
const selection = d3.select(this);
|
||||
selection.attr('stroke', 'var(--wire-color)');
|
||||
});
|
||||
|
||||
// linesContainer.each(function(lines) {
|
||||
// // 为每一个线段分别创建对应的对象
|
||||
// const lineSelection = d3.select(this)
|
||||
// .selectAll('.line')
|
||||
// .data(lines)
|
||||
// .enter()
|
||||
// .append('line')
|
||||
// .attr('x1', data => data.x1)
|
||||
// .attr('y1', data => data.y1)
|
||||
// .attr('x2', data => data.x2)
|
||||
// .attr('y2', data => data.y2)
|
||||
// .attr('stroke', 'var(--wire-color)');
|
||||
|
||||
// lineSelection.on('mouseenter', function(_, data) {
|
||||
// console.log('enter enter');
|
||||
// });
|
||||
|
||||
// lineSelection.on('mouseleave', function(_, data) {
|
||||
// console.log('enter leave');
|
||||
// });
|
||||
|
||||
// lineSelection.on('click', function(_, data) {
|
||||
// console.log('click');
|
||||
// });
|
||||
// });
|
||||
|
||||
if (globalSetting.renderAnimation) {
|
||||
lineSelections = lineSelections
|
||||
.transition()
|
||||
@ -64,7 +158,7 @@ export class WireRender {
|
||||
}
|
||||
|
||||
lineSelections
|
||||
.attr('stroke-width', data => data.strokeWidth)
|
||||
.attr('stroke-width', LINE_WIDTH)
|
||||
.each(function (data) {
|
||||
const selection = d3.select(this);
|
||||
// const manager = _this.createDataManager(selection, data);
|
||||
@ -93,4 +187,16 @@ export class WireRender {
|
||||
id2manager.get(data.id).push(managerItem);
|
||||
return managerItem;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 计算贝塞尔插值,输入 0 - 1 的值 (delta),输出 [oldVal, newVal] 中间的插值
|
||||
* @param {*} delta
|
||||
* @param {*} oldVal
|
||||
* @param {*} newVal
|
||||
* @returns
|
||||
*/
|
||||
function cubicBezierAnimation(delta, oldVal, newVal) {
|
||||
delta = 3 * (1 - delta) * (1 - delta) * delta + 3 * (1 - delta) * delta * delta + delta * delta * delta;
|
||||
return (1 - delta) * oldVal + delta * newVal;
|
||||
}
|
@ -24,5 +24,6 @@
|
||||
"common.port": "المنفذ",
|
||||
"common.instance": "تجهيز الوحدة",
|
||||
"setting.general-color-setting": "إعدادات الألوان العامة",
|
||||
"cross-dot": "تقاطع"
|
||||
"cross-dot": "تقاطع",
|
||||
"common.selected-wire": "الخط المحدد"
|
||||
}
|
@ -24,5 +24,6 @@
|
||||
"common.port": "Port",
|
||||
"common.instance": "Modul instanziieren",
|
||||
"setting.general-color-setting": "Allgemeine Farbeinstellungen",
|
||||
"cross-dot": "Kreuzung"
|
||||
"cross-dot": "Kreuzung",
|
||||
"common.selected-wire": "Ausgewählte Linie"
|
||||
}
|
@ -24,5 +24,6 @@
|
||||
"common.port": "Port",
|
||||
"common.instance": "Instantiate module",
|
||||
"setting.general-color-setting": "General Color Settings",
|
||||
"cross-dot": "Intersection"
|
||||
"cross-dot": "Intersection",
|
||||
"common.selected-wire": "Selected line"
|
||||
}
|
@ -24,5 +24,6 @@
|
||||
"common.port": "Port",
|
||||
"common.instance": "Instancier le module",
|
||||
"setting.general-color-setting": "Paramètres de couleur généraux",
|
||||
"cross-dot": "Intersection"
|
||||
"cross-dot": "Intersection",
|
||||
"common.selected-wire": "Ligne sélectionnée"
|
||||
}
|
@ -24,5 +24,6 @@
|
||||
"common.port": "ポート",
|
||||
"common.instance": "モジュールのインスタンス化",
|
||||
"setting.general-color-setting": "一般的な色設定",
|
||||
"cross-dot": "交差点"
|
||||
"cross-dot": "交差点",
|
||||
"common.selected-wire": "選択された線"
|
||||
}
|
@ -24,5 +24,6 @@
|
||||
"common.port": "포트",
|
||||
"common.instance": "모듈 인스턴스화",
|
||||
"setting.general-color-setting": "일반 색상 설정",
|
||||
"cross-dot": "교차로"
|
||||
"cross-dot": "교차로",
|
||||
"common.selected-wire": "선택된 선"
|
||||
}
|
@ -24,5 +24,6 @@
|
||||
"common.port": "Порт",
|
||||
"common.instance": "Создание экземпляра модуля",
|
||||
"setting.general-color-setting": "Общие настройки цвета",
|
||||
"cross-dot": "Перекресток"
|
||||
"cross-dot": "Перекресток",
|
||||
"common.selected-wire": "Выбранная линия"
|
||||
}
|
@ -24,5 +24,6 @@
|
||||
"common.port": "端口",
|
||||
"common.instance": "例化模块",
|
||||
"setting.general-color-setting": "通用颜色设置",
|
||||
"cross-dot": "交叉点"
|
||||
"cross-dot": "交叉点",
|
||||
"common.selected-wire": "被选中的线"
|
||||
}
|
@ -24,5 +24,6 @@
|
||||
"common.port": "端口",
|
||||
"common.instance": "實例化模組",
|
||||
"setting.general-color-setting": "通用顏色設定",
|
||||
"cross-dot": "交叉點"
|
||||
"cross-dot": "交叉點",
|
||||
"common.selected-wire": "被選中的線"
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user