1、环境设置与启动项目
从git下载代码,进入到packages/core文件夹,cnpm install(或者yarn)安装相关依赖包。npm run dev启动项目,访问http://localhost:9090/ 至此LogicFlow core项目已经正常启动了。
2、代码流程梳理
0、起步
import LogicFlow from '@logicflow/core';
const config = {
isSilentMode: true,
stopScrollGraph: true,
stopZoomGraph: true,
style: {
rect: {
width: 100,
height: 50
}
}
}
const data = {
nodes: [
{
id: 10,
type: 'rect',
x: 150,
y: 70,
text: '矩形1'
}
]
};
const lf = new LogicFlow({
...config,
container: document.querySelector('#graph') as HTMLElement
});
lf.render(data);
从上面的使用方法可以看出,入口是LogicFlow,先new LogicFlow({})调用LogicFlow的构造函数,之后lf.render(data)绘制data数据到页面中用svg展示。
1、LogicFlow.tsx
这是项目的入口文件,文件中定义了class LogicFlow, 其包含需多的方法,根据例子中代码的执行到lf.render(data);,从LogicFlow的render开始(构造函数会初始化一些参数,用到的参数会详细说明)。
import { render, h } from 'preact';
export default class LogicFlow {
constructor(options: Options.Definition) {}
render(graphData = {}) {//代码有省略
this.graphModel.graphDataToModel(graphData);
render((
<Provider
graphModel={this.graphModel}
>
<Graph
eventCenter={this.eventCenter}
getView={this.getView}
tool={this.tool}
options={this.options}
dnd={this.dnd}
snaplineModel={this.snaplineModel}
components={this.components}
/>
</Provider>
), this.container);
}
}
外层的render函数是LogicFlow中的,内层的render是preact中的。 render中执行this.graphModel.graphDataToModel(graphData),代码调用GraphModel.ts中的graphDataToModel方法,设置nodes和edges,代码如下
graphDataToModel(graphData) {//代码有省略
this.nodes = map(graphData.nodes, node => {
const Model = this.getModel(node.type);
return new Model(node, this);
});
this.edges = map(graphData.edges, edge => {
const Model = this.getModel(edge.type);
return new Model(edge, this);
});
}
getModel(type: string) {
return this.modelMap.get(type);
}
其中调用this.getModel(type: string)获取Model,函数this.getModel中的this.modelMap的内容是在LogicFlow.tsx中调用 this.graphModel.setModel(type, ModelClass);进行写入的。
代码new Model(node, this);中的Model最终可以找到RectNodeModel.ts中。
import { computed, observable } from 'mobx';
class RectNodeModel extends BaseNodeModel {
modelType = ModelType.RECT_NODE;
@observable width = defaultTheme.rect.width;
@observable height = defaultTheme.rect.height;
@observable radius = defaultTheme.rect.radius;
}
export default class BaseNodeModel implements IBaseModel {}
RectNodeModel继承了BaseNodeModel,两个类中的很多属性前添加了@observable注解(observable表示属性是可观测的,当属性被改变时,将会触发组件的重新渲染展示在页面中)。
到这里,执行第二个render函数把this.graphModel传递给Provider了。
<Provider graphModel={this.graphModel}>
<Graph
/>
</Provider>
2、Graph.tsx
LogicFlow的第二个render函数执行渲染,会进入到Graph.tsx组件中。
import { observer, inject } from 'mobx-react';
@inject('graphModel')
@observer
class Graph extends Component<IProps> {//这是一个组件
render() {
return (<div>
<CanvasOverlay>
<g className="lf-base">
{
map(graphModel.sortElements, (nodeModel) => (
this.getComponent(nodeModel, graphModel, eventCenter)
))
}
</g>
</CanvasOverlay>
</div>)
}
}
在Graph.tsx中,@inject('graphModel')会引入Provider组件中提供的graphModel参数,至此Graph组件中的this.props属性中含有了graphModel。
Graph.tsx中render的return中使用了CanvasOverlay组件
class CanvasOverlay extends Component<IProps, Istate> {
render() {
const { transformStyle: { transform } } = this.InjectedProps;
const { children, dnd } = this.props;
const { isDraging } = this.state;
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="100%"
height="100%"
name="canvas-overlay"
onWheel={this.zoomHandler}
onMouseDown={this.mouseDownHandler}
onContextMenu={this.handleContextMenu}
className={isDraging ? 'lf-dragging' : 'lf-drag-able'}
{...dnd.eventMap()}
>
<g style={{ transform }}>
{children}
</g>
</svg>
);
}
}
CanvasOverlay组件中使用的children,就是Graph提供的。
<g className="lf-base">
{
map(graphModel.sortElements, (nodeModel) => (
this.getComponent(nodeModel, graphModel, eventCenter)
))
}
</g>
this.getComponent函数还在Graph.tsx中。
getComponent() {
const { getView } = this.props;
const View = getView(model.type);//'rect'
return (
<View
key={model.id}
model={model}
graphModel={graphModel}
overlay={overlay}
eventCenter={eventCenter}
/>
);
}
getView(model.type)函数在LogicFlow.tsx中。
getView = (type: string) => this.viewMap.get(type);
this.viewMap中的数据内容是通过this.setView(type, observer(ViewClass as IReactComponent));
写入的。
最终可以找到RectNode.tsx中。
3、RectNode.tsx
export default class RectNode extends BaseNode {
getShape() {
const attributes = this.getAttributes();
return (
<Rect
{...attributes}
/>
);
}
}
export default abstract class BaseNode extends Component<IProps, Istate> {
render() {
const nodeShapeInner = (
<g className="lf-node-content">
{this.getShape()}
{this.getText()}
</g>
);
let nodeShape;
if (!isHitable) {
nodeShape = (
<g className={this.getStateClassName()} id={model.id}>
{ nodeShapeInner }
</g>
);
} else {
nodeShape = (
<g
className={this.getStateClassName()}
id={model.id}
onMouseDown={this.handleMouseDown}
onMouseUp={this.handleClick}
onMouseEnter={this.setHoverON}
onMouseLeave={this.setHoverOFF}
onContextMenu={this.handleContextMenu}
>
{ nodeShapeInner }
</g>
);
}
return nodeShape;
}
}
RectNode继承自BaseNode,变成了是一个组件,继承了BaseNode中的render函数。在render函数中调用this.getShape()<Rect {...attributes} />
组件。
4、Rect.tsx
export default function Rect(props: IProps) {
return (
<rect {...attrs} />
);
}
这是一个函数组件,是最终渲染到页面中svg标签内的rect标签。
至此上面实例中rect矩形被成功渲染到了页面中。
3、详解
未完待续。。。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!