更新架构,进行依赖注入
This commit is contained in:
parent
e06f6abc50
commit
b718780cf5
@ -223,14 +223,14 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef BasicD3ManagmentItem
|
||||
* @typedef BasicD3ManagmentItem 用于管理一个 实体/连接 的 d3 上下文数据结构
|
||||
* @property {'cell' | 'connection' | 'instantiation' | 'port' | 'wire'} type
|
||||
* @property {BasicD3DataItem} data
|
||||
* @property {d3.Selection} selection
|
||||
* @property {BasicD3DataItem} data 用于绑定 d3 渲染的数据,【初始化/特殊事件】会使得 d3 去主动根据
|
||||
* @property {d3.Selection} selection 渲染成图形对应的 d3 选择集
|
||||
* @property {DragContext} [dragContext] 与当前这个 实体 相关的拖拽上下文(目前不支持 wire 和 connection 的)
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef DragContext
|
||||
* @property {BasicD3DataItem} data
|
||||
* @property {ElkGraph} elkGraph
|
||||
*/
|
@ -21,7 +21,7 @@ export class CellRender {
|
||||
* @description id 到管理数据项的映射
|
||||
* @type {Map<string, BasicD3ManagmentItem[]>}
|
||||
*/
|
||||
this.id2selections = rootRender.id2selections;
|
||||
this.id2manager = rootRender.id2manager;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,7 +44,8 @@ export class CellRender {
|
||||
render() {
|
||||
const data = this.data;
|
||||
const rootRender = this.rootRender;
|
||||
const id2selections = this.id2selections;
|
||||
const id2manager = this.id2manager;
|
||||
const _this = this;
|
||||
|
||||
let cellSelections = this.parentSelection.selectAll('svg')
|
||||
.data(data)
|
||||
@ -67,74 +68,83 @@ export class CellRender {
|
||||
.attr('class', 'grab')
|
||||
.on('end', function (data) {
|
||||
const cellSelection = d3.select(this);
|
||||
registerDragEvent(cellSelection, data, rootRender);
|
||||
const manager = _this.createDataManager(cellSelection, data);
|
||||
registerDragEvent(manager, rootRender);
|
||||
});
|
||||
} else {
|
||||
cellSelections = cellSelections
|
||||
.attr('class', 'grab')
|
||||
.each(function (data) {
|
||||
const cellSelection = d3.select(this);
|
||||
registerDragEvent(cellSelection, data, rootRender);
|
||||
const manager = _this.createDataManager(cellSelection, data);
|
||||
registerDragEvent(manager, rootRender);
|
||||
});
|
||||
}
|
||||
|
||||
cellSelections.each(function (data) {
|
||||
const selection = d3.select(this);
|
||||
if (!id2selections.has(data.id)) {
|
||||
id2selections.set(data.id, []);
|
||||
}
|
||||
id2selections.get(data.id).push({
|
||||
data,
|
||||
selection,
|
||||
type: 'cell'
|
||||
});
|
||||
});
|
||||
|
||||
this.selections = cellSelections;
|
||||
return cellSelections;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {d3.Selection} selection
|
||||
* @param {BasicD3DataItem} data
|
||||
* @returns {BasicD3ManagmentItem}
|
||||
*/
|
||||
createDataManager(selection, data) {
|
||||
const id2manager = this.id2manager;
|
||||
// 创建拖拽上下文
|
||||
const dragContext = {
|
||||
elkGraph: {
|
||||
// elk 是无状态的,id 取什么名字都行
|
||||
id: 'root',
|
||||
children: [],
|
||||
edges: [],
|
||||
layoutOptions: {}
|
||||
}
|
||||
}
|
||||
const managerItem = {
|
||||
data,
|
||||
selection,
|
||||
type: 'cell',
|
||||
dragContext
|
||||
};
|
||||
|
||||
if (!id2manager.has(data.id)) {
|
||||
id2manager.set(data.id, []);
|
||||
}
|
||||
|
||||
id2manager.set(data.id, managerItem);
|
||||
return managerItem;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 注册关于 器件 的拖动事件
|
||||
*
|
||||
* 需要提取最小拓扑子图,然后重新调整各个区域的尺寸
|
||||
* @param {d3.Selection} selection
|
||||
* @param {any} data
|
||||
* @param {BasicD3ManagmentItem} manager
|
||||
* @param {NetlistRender} rootRender
|
||||
*/
|
||||
export function registerDragEvent(selection, data, rootRender) {
|
||||
export function registerDragEvent(manager, rootRender) {
|
||||
// 创建拖拽行为
|
||||
const drag = d3.drag();
|
||||
|
||||
const dragContext = {
|
||||
data: data,
|
||||
elkGraph: {
|
||||
id: 'root',
|
||||
children: [],
|
||||
edges: [],
|
||||
layoutOptions: {
|
||||
// 伟大,无需多言
|
||||
'elk.algorithm': ''
|
||||
}
|
||||
}
|
||||
}
|
||||
drag.on('start', async event => dragStart(event, manager, rootRender));
|
||||
drag.on('drag', async event => dragged(event, manager, rootRender));
|
||||
drag.on('end', async event => dragEnd(event, manager, rootRender))
|
||||
|
||||
drag.on('start', async event => dragStart(event, selection, dragContext, rootRender));
|
||||
drag.on('drag', async event => dragged(event, selection, dragContext, rootRender));
|
||||
drag.on('end', async event => dragEnd(event, selection, dragContext, rootRender))
|
||||
|
||||
selection.call(drag);
|
||||
manager.selection.call(drag);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {d3.D3DragEvent} event
|
||||
* @param {d3.Selection} selection
|
||||
* @param {DragContext} dragContext
|
||||
* @param {BasicD3ManagmentItem} manager
|
||||
* @param {NetlistRender} rootRender
|
||||
*/
|
||||
function dragStart(event, selection, dragContext, rootRender) {
|
||||
function dragStart(event, manager, rootRender) {
|
||||
const selection = manager.selection;
|
||||
selection.attr('class', 'grabbing');
|
||||
|
||||
// 更新拓扑图中各个节点的节点坐标
|
||||
@ -145,32 +155,34 @@ function dragStart(event, selection, dragContext, rootRender) {
|
||||
/**
|
||||
*
|
||||
* @param {d3.D3DragEvent} event
|
||||
* @param {d3.Selection} selection
|
||||
* @param {DragContext} dragContext
|
||||
* @param {BasicD3ManagmentItem} manager
|
||||
* @param {NetlistRender} rootRender
|
||||
*/
|
||||
function dragged(event, selection, dragContext, rootRender) {
|
||||
function dragged(event, manager, rootRender) {
|
||||
// 当拖动结束时,D3 会根据绑定的数据(data.x 和 data.y)重新渲染元素,导致元素回到初始位置。
|
||||
// 所以需要 手动更新 data.x 和 data.y
|
||||
dragContext.data.x = event.x;
|
||||
dragContext.data.y = event.y;
|
||||
const selection = manager.selection;
|
||||
const data = manager.data;
|
||||
|
||||
data.x = event.x;
|
||||
data.y = event.y;
|
||||
|
||||
selection
|
||||
.attr('x', event.x)
|
||||
.attr('y', event.y);
|
||||
|
||||
// 根据最小拓扑图,提取出关键点,重新计算布局
|
||||
console.log(dragContext.data);
|
||||
|
||||
const context = manager.dragContext;
|
||||
console.log(context.elkGraph);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {d3.D3DragEvent} event
|
||||
* @param {d3.Selection} selection
|
||||
* @param {DragContext} dragContext
|
||||
* @param {BasicD3ManagmentItem} manager
|
||||
* @param {NetlistRender} rootRender
|
||||
*/
|
||||
function dragEnd(event, selection, dragContext, rootRender) {
|
||||
function dragEnd(event, manager, rootRender) {
|
||||
const selection = manager.selection;
|
||||
selection.attr('class', 'grab');
|
||||
}
|
@ -20,7 +20,7 @@ export class ConnectionRender {
|
||||
* @description id 到管理数据项的映射
|
||||
* @type {Map<string, BasicD3ManagmentItem[]>}
|
||||
*/
|
||||
this.id2selections = rootRender.id2selections;
|
||||
this.id2manager = rootRender.id2manager;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -43,7 +43,8 @@ export class ConnectionRender {
|
||||
|
||||
render() {
|
||||
const data = this.data;
|
||||
const id2selections = this.id2selections;
|
||||
const id2manager = this.id2manager;
|
||||
const _this = this;
|
||||
|
||||
let connectionSelections = this.parentSelection.selectAll('circle')
|
||||
.data(data)
|
||||
@ -65,17 +66,33 @@ export class ConnectionRender {
|
||||
.attr('r', d => d.r)
|
||||
.each(function (data) {
|
||||
const selection = d3.select(this);
|
||||
if (!id2selections.has(data.id)) {
|
||||
id2selections.set(data.id, []);
|
||||
}
|
||||
id2selections.get(data.id).push({
|
||||
data,
|
||||
selection,
|
||||
type: 'connection'
|
||||
});
|
||||
const manager = _this.createDataManager(selection, data);
|
||||
});
|
||||
|
||||
this.selections = connectionSelections;
|
||||
return connectionSelections;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {d3.Selection} selection
|
||||
* @param {BasicD3DataItem} data
|
||||
* @returns {BasicD3ManagmentItem}
|
||||
*/
|
||||
createDataManager(selection, data) {
|
||||
const id2manager = this.id2manager;
|
||||
// connection 不需要拖拽上下文
|
||||
const managerItem = {
|
||||
data,
|
||||
selection,
|
||||
type: 'connection'
|
||||
};
|
||||
|
||||
if (!id2manager.has(data.id)) {
|
||||
id2manager.set(data.id, []);
|
||||
}
|
||||
|
||||
id2manager.set(data.id, managerItem);
|
||||
return managerItem;
|
||||
}
|
||||
}
|
||||
|
@ -62,9 +62,13 @@ export class NetlistRender {
|
||||
|
||||
/**
|
||||
* @description id 到管理数据项的映射
|
||||
*
|
||||
* - key: id, 和 layout.js 中的赋值 id 一致,全局唯一
|
||||
* - value: 每一个 id 对应的管理者,这里存储着数据视图和渲染视图,查询与操作DOM一体。一个 ID 对应的真实渲染体可能不只一个
|
||||
* (比如对于 wire,一个 id 对应的 wire 可以是连续的折现,但是这些折现对应的渲染体是复数个的)
|
||||
* @type {Map<string, BasicD3ManagmentItem[]>}
|
||||
*/
|
||||
this.id2selections = new Map();
|
||||
this.id2manager = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,7 +20,7 @@ export class InstantiationRender {
|
||||
* @description id 到管理数据项的映射
|
||||
* @type {Map<string, BasicD3ManagmentItem[]>}
|
||||
*/
|
||||
this.id2selections = rootRender.id2selections;
|
||||
this.id2manager = rootRender.id2manager;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,7 +22,7 @@ export class PortRender {
|
||||
* @description id 到管理数据项的映射
|
||||
* @type {Map<string, BasicD3ManagmentItem[]>}
|
||||
*/
|
||||
this.id2selections = rootRender.id2selections;
|
||||
this.id2manager = rootRender.id2manager;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -45,7 +45,9 @@ export class PortRender {
|
||||
|
||||
render() {
|
||||
const data = this.data;
|
||||
const id2selections = this.id2selections;
|
||||
const id2manager = this.id2manager;
|
||||
const rootRender = this.rootRender;
|
||||
const _this = this;
|
||||
|
||||
let portSelections = this.parentSelection.selectAll('g.port')
|
||||
.data(data)
|
||||
@ -60,8 +62,8 @@ export class PortRender {
|
||||
.attr('fill', d => d.fill);
|
||||
|
||||
let texts = portSelections.append('text')
|
||||
.attr('x', data => data.width / 2) // 文本的 x 坐标(居中)
|
||||
.attr('y', data => data.height / 2) // 文本的 y 坐标(居中)
|
||||
.attr('x', data => data.width / 2) // 文本的 x 坐标(居中)
|
||||
.attr('y', data => data.height / 2) // 文本的 y 坐标(居中)
|
||||
.attr('dominant-baseline', 'middle') // 文本垂直居中
|
||||
.attr('text-anchor', 'middle') // 文本水平居中
|
||||
.attr('fill', 'var(--foreground)') // 文本颜色
|
||||
@ -70,7 +72,7 @@ export class PortRender {
|
||||
.duration(1000)
|
||||
.attr('font-size', '12px')
|
||||
.attr('class', 'port-caption')
|
||||
.text(data => data.text); // 设置文本内容
|
||||
.text(data => data.text); // 设置文本内容
|
||||
|
||||
|
||||
if (globalSetting.renderAnimation) {
|
||||
@ -91,18 +93,46 @@ export class PortRender {
|
||||
.attr('class', 'grab')
|
||||
.each(function (data) {
|
||||
const portSelection = d3.select(this);
|
||||
// 注册拖拽
|
||||
registerDragEvent(portSelection, data);
|
||||
// 进行管理
|
||||
if (!id2selections.has(data.id)) {
|
||||
id2selections.set(data.id, []);
|
||||
}
|
||||
id2selections.get(data.id).push({ data, selection: portSelection });
|
||||
const manager = _this.createDataManager(portSelection, data);
|
||||
registerDragEvent(manager, rootRender);
|
||||
});
|
||||
|
||||
this.selections = portSelections;
|
||||
return portSelections;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {d3.Selection} selection
|
||||
* @param {BasicD3DataItem} data
|
||||
* @returns {BasicD3ManagmentItem}
|
||||
*/
|
||||
createDataManager(selection, data) {
|
||||
const id2manager = this.id2manager;
|
||||
// 创建拖拽上下文
|
||||
const dragContext = {
|
||||
elkGraph: {
|
||||
// elk 是无状态的,id 取什么名字都行
|
||||
id: 'root',
|
||||
children: [],
|
||||
edges: [],
|
||||
layoutOptions: {}
|
||||
}
|
||||
}
|
||||
const managerItem = {
|
||||
data,
|
||||
selection,
|
||||
type: 'port',
|
||||
dragContext
|
||||
};
|
||||
|
||||
if (!id2manager.has(data.id)) {
|
||||
id2manager.set(data.id, []);
|
||||
}
|
||||
|
||||
id2manager.set(data.id, managerItem);
|
||||
return managerItem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -112,45 +142,50 @@ export class PortRender {
|
||||
* @description 注册关于 器件 的拖动事件
|
||||
*
|
||||
* 需要提取最小拓扑子图,然后重新调整各个区域的尺寸
|
||||
* @param {d3.Selection} selection
|
||||
* @param {any} data
|
||||
* @param {BasicD3ManagmentItem} manager
|
||||
* @param {NetlistRender} rootRender
|
||||
*/
|
||||
export function registerDragEvent(selection, data) {
|
||||
export function registerDragEvent(manager, rootRender) {
|
||||
// 创建拖拽行为
|
||||
const drag = d3.drag();
|
||||
|
||||
drag.on("start", event => dragStart(event, selection, data));
|
||||
drag.on("drag", event => dragged(event, selection, data));
|
||||
drag.on("end", event => dragEnd(event, selection, data));
|
||||
drag.on("start", event => dragStart(event, manager, rootRender));
|
||||
drag.on("drag", event => dragged(event, manager, rootRender));
|
||||
drag.on("end", event => dragEnd(event, manager, rootRender));
|
||||
|
||||
selection.call(drag);
|
||||
manager.selection.call(drag);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {d3.D3DragEvent} event
|
||||
* @param {d3.Selection} selection
|
||||
* @param {BasicD3ManagmentItem} manager
|
||||
* @param {NetlistRender} rootRender
|
||||
*/
|
||||
function dragStart(event, selection, data) {
|
||||
function dragStart(event, manager, rootRender) {
|
||||
const selection = manager.selection;
|
||||
selection.attr('class', 'grabbing');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {d3.D3DragEvent} event
|
||||
* @param {d3.Selection} selection
|
||||
* @param {BasicD3ManagmentItem} manager
|
||||
* @param {NetlistRender} rootRender
|
||||
*/
|
||||
function dragged(event, selection, data) {
|
||||
function dragged(event, manager, rootRender) {
|
||||
const selection = manager.selection;
|
||||
const data = manager.data;
|
||||
|
||||
data.x = event.x;
|
||||
data.y = event.y;
|
||||
selection.attr("transform", `translate(${event.x}, ${event.y})`);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {d3.D3DragEvent} event
|
||||
* @param {d3.Selection} selection
|
||||
* @param {BasicD3ManagmentItem} manager
|
||||
* @param {NetlistRender} rootRender
|
||||
*/
|
||||
function dragEnd(event, selection, data) {
|
||||
function dragEnd(event, manager, rootRender) {
|
||||
const selection = manager.selection;
|
||||
selection.attr('class', 'grab');
|
||||
}
|
@ -21,7 +21,7 @@ export class WireRender {
|
||||
* @description id 到管理数据项的映射
|
||||
* @type {Map<string, BasicD3ManagmentItem[]>}
|
||||
*/
|
||||
this.id2selections = rootRender.id2selections;
|
||||
this.id2manager = rootRender.id2manager;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -45,7 +45,8 @@ export class WireRender {
|
||||
|
||||
render() {
|
||||
const data = this.data;
|
||||
const id2selections = this.id2selections;
|
||||
const id2manager = this.id2manager;
|
||||
const _this = this;
|
||||
|
||||
let lineSelections = this.selection.selectAll('line')
|
||||
.data(data)
|
||||
@ -67,10 +68,30 @@ export class WireRender {
|
||||
.attr('stroke-width', data => data.strokeWidth)
|
||||
.each(function (data) {
|
||||
const selection = d3.select(this);
|
||||
if (!id2selections.has(data.id)) {
|
||||
id2selections.set(data.id, []);
|
||||
}
|
||||
id2selections.get(data.id).push({ data, selection });
|
||||
const manager = _this.createDataManager(selection, data);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {d3.Selection} selection
|
||||
* @param {BasicD3DataItem} data
|
||||
* @returns {BasicD3ManagmentItem}
|
||||
*/
|
||||
createDataManager(selection, data) {
|
||||
const id2manager = this.id2manager;
|
||||
// wire 不需要拖拽上下文
|
||||
const managerItem = {
|
||||
data,
|
||||
selection,
|
||||
type: 'wire'
|
||||
};
|
||||
|
||||
if (!id2manager.has(data.id)) {
|
||||
id2manager.set(data.id, []);
|
||||
}
|
||||
|
||||
id2manager.set(data.id, managerItem);
|
||||
return managerItem;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user