fix: 新增可以修改整体样式的接口
This commit is contained in:
parent
e1a69b5e91
commit
3626a6eb19
@ -6,7 +6,7 @@ SV.registerLayout('Array', {
|
||||
sourcesPreprocess(sources) {
|
||||
const firstElement = sources[0];
|
||||
|
||||
if(firstElement.external) {
|
||||
if (firstElement.external) {
|
||||
firstElement.headExternal = firstElement.external;
|
||||
delete firstElement.external;
|
||||
}
|
||||
@ -18,7 +18,7 @@ SV.registerLayout('Array', {
|
||||
return {
|
||||
node: {
|
||||
default: {
|
||||
type: 'rect',
|
||||
type: 'array-node',
|
||||
label: '[id]',
|
||||
size: [60, 30],
|
||||
labelOptions: {
|
||||
@ -56,77 +56,13 @@ SV.registerLayout('Array', {
|
||||
layout(elements) {
|
||||
let arr = elements;
|
||||
|
||||
for(let i = 0; i < arr.length; i++) {
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
let width = arr[i].get('size')[0];
|
||||
|
||||
if(i > 0) {
|
||||
if (i > 0) {
|
||||
arr[i].set('x', arr[i - 1].get('x') + width);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
SV.registerLayout('Array', {
|
||||
|
||||
sourcesPreprocess(sources) {
|
||||
const firstElement = sources[0];
|
||||
|
||||
if(firstElement.external) {
|
||||
firstElement.headExternal = firstElement.external;
|
||||
delete firstElement.external;
|
||||
}
|
||||
|
||||
return sources;
|
||||
},
|
||||
|
||||
defineOptions() {
|
||||
return {
|
||||
node: {
|
||||
default: {
|
||||
type: 'indexed-node',
|
||||
label: '[id]',
|
||||
size: [60, 30],
|
||||
style: {
|
||||
stroke: '#333',
|
||||
fill: '#355c7d'
|
||||
}
|
||||
}
|
||||
},
|
||||
marker: {
|
||||
headExternal: {
|
||||
type: 'pointer',
|
||||
anchor: 3,
|
||||
style: {
|
||||
fill: '#f08a5d'
|
||||
}
|
||||
},
|
||||
external: {
|
||||
type: 'pointer',
|
||||
anchor: 0,
|
||||
style: {
|
||||
fill: '#f08a5d'
|
||||
}
|
||||
}
|
||||
},
|
||||
indexLabel: {
|
||||
index: { position: 'bottom' },
|
||||
indexTop: { position: 'top' }
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
layout(elements) {
|
||||
let arr = elements;
|
||||
|
||||
for(let i = 0; i < arr.length; i++) {
|
||||
let width = arr[i].get('size')[0];
|
||||
|
||||
if(i > 0) {
|
||||
arr[i].set('x', arr[i - 1].get('x') + width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 'colorful');
|
@ -100,27 +100,8 @@
|
||||
|
||||
|
||||
let data = [{
|
||||
PTree: {
|
||||
data: [
|
||||
{
|
||||
id: '1001',
|
||||
data: 'A',
|
||||
parent: -1,
|
||||
index: 0
|
||||
},
|
||||
{
|
||||
id: '1002',
|
||||
data: 'B',
|
||||
parent: 0,
|
||||
index: 1
|
||||
},
|
||||
],
|
||||
layouter: 'PTree'
|
||||
|
||||
}
|
||||
}, {
|
||||
Array: {
|
||||
data: [{ id: 1, data: 1 }, { id: 2, data: 2 }, { id: 3, data: 3 }],
|
||||
data: [{ id: 1, data: 1, external: 'list' }, { id: 2, data: 2 }, { id: 3, data: 3 }],
|
||||
layouter: 'Array'
|
||||
}
|
||||
}, {
|
||||
@ -172,7 +153,7 @@
|
||||
});
|
||||
|
||||
document.getElementById('switch-mode').addEventListener('click', e => {
|
||||
cur.switchMode('Array', 'colorful');
|
||||
cur.updateStyle('Array', newArrayOption);
|
||||
});
|
||||
|
||||
const leak = document.getElementById('leak');
|
||||
|
40
dist/sv.js
vendored
40
dist/sv.js
vendored
File diff suppressed because one or more lines are too long
@ -1,8 +1,10 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@antv/g6": "^4.4.1"
|
||||
"@antv/g6": "^4.4.1",
|
||||
"merge": "^2.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"merge": "^2.1.1",
|
||||
"ts-loader": "^5.2.1",
|
||||
"typescript": "^3.2.2",
|
||||
"webpack": "^4.46.0",
|
||||
|
@ -24,8 +24,7 @@ export class SVLink extends SVModel {
|
||||
this.G6ModelProps = this.generateG6ModelProps(options);
|
||||
}
|
||||
|
||||
|
||||
protected generateG6ModelProps(options: LinkOption): EdgeConfig {
|
||||
generateG6ModelProps(options: LinkOption): EdgeConfig {
|
||||
let sourceAnchor = options.sourceAnchor,
|
||||
targetAnchor = options.targetAnchor;
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { Style } from "../options";
|
||||
import { BoundingRect } from "../Common/boundingRect";
|
||||
import { EdgeConfig, Item, NodeConfig } from "@antv/g6-core";
|
||||
import { Graph } from "_@antv_g6-pc@0.5.0@@antv/g6-pc";
|
||||
|
||||
import merge from 'merge';
|
||||
|
||||
|
||||
|
||||
@ -52,7 +52,7 @@ export class SVModel {
|
||||
* 定义 G6 model 的属性
|
||||
* @param option
|
||||
*/
|
||||
protected generateG6ModelProps(options: unknown) {
|
||||
generateG6ModelProps(options: unknown): NodeConfig | EdgeConfig {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ export class SVModel {
|
||||
}
|
||||
|
||||
if (attr === 'style' || attr === 'labelCfg') {
|
||||
Object.assign(this.G6ModelProps[attr], value);
|
||||
this.G6ModelProps[attr] = merge(this.G6ModelProps[attr] || {}, value);
|
||||
}
|
||||
else {
|
||||
this.G6ModelProps[attr] = value;
|
||||
@ -115,6 +115,31 @@ export class SVModel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param G6ModelProps
|
||||
*/
|
||||
updateG6ModelStyle(G6ModelProps: NodeConfig | EdgeConfig) {
|
||||
const newG6ModelProps = {
|
||||
style: {
|
||||
...G6ModelProps.style
|
||||
},
|
||||
labelCfg: {
|
||||
...G6ModelProps.labelCfg
|
||||
}
|
||||
};
|
||||
|
||||
this.G6ModelProps = merge(this.G6ModelProps, newG6ModelProps);
|
||||
|
||||
if (this.G6Item) {
|
||||
this.g6Instance.updateItem(this.G6Item, this.G6ModelProps);
|
||||
}
|
||||
|
||||
if (this.shadowG6Item) {
|
||||
this.shadowG6Instance.updateItem(this.shadowG6Item, this.G6ModelProps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取包围盒
|
||||
* @returns
|
||||
|
@ -51,7 +51,7 @@ export class SVNode extends SVModel {
|
||||
this.G6ModelProps = this.generateG6ModelProps(options);
|
||||
}
|
||||
|
||||
protected generateG6ModelProps(options: NodeOption): NodeConfig {
|
||||
generateG6ModelProps(options: NodeOption): NodeConfig {
|
||||
const style = Util.objectClone<Style>(options.style);
|
||||
|
||||
return {
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { INode, NodeConfig } from "@antv/g6-core";
|
||||
import { INode, NodeConfig, EdgeConfig } from "@antv/g6-core";
|
||||
import { Util } from "../Common/util";
|
||||
import { AddressLabelOption, IndexLabelOption, MarkerOption, NodeLabelOption, Style } from "../options";
|
||||
import { SourceNode } from "../sources";
|
||||
import { SVModel } from "./SVModel";
|
||||
import { SVNode } from "./SVNode";
|
||||
|
||||
@ -108,7 +107,7 @@ export class SVIndexLabel extends SVNodeAppendage {
|
||||
this.G6ModelProps = this.generateG6ModelProps(options) as NodeConfig;
|
||||
}
|
||||
|
||||
generateG6ModelProps(options: IndexLabelOption) {
|
||||
generateG6ModelProps(options: IndexLabelOption): NodeConfig | EdgeConfig {
|
||||
return {
|
||||
id: this.id,
|
||||
x: 0,
|
||||
@ -155,7 +154,7 @@ export class SVMarker extends SVNodeAppendage {
|
||||
this.G6ModelProps = this.generateG6ModelProps(options);
|
||||
}
|
||||
|
||||
protected generateG6ModelProps(options: MarkerOption): NodeConfig {
|
||||
generateG6ModelProps(options: MarkerOption): NodeConfig {
|
||||
this.anchor = options.anchor;
|
||||
|
||||
const type = options.type,
|
||||
|
@ -44,13 +44,12 @@ export class ModelConstructor {
|
||||
*/
|
||||
public construct(sources: Sources): LayoutGroupTable {
|
||||
const layoutGroupTable = new Map<string, LayoutGroup>(),
|
||||
layoutMap: { [key: string]: { [key: string]: LayoutCreator } } = SV.registeredLayout;
|
||||
layoutMap: { [key: string]: LayoutCreator } = SV.registeredLayout;
|
||||
|
||||
Object.keys(sources).forEach(group => {
|
||||
let sourceGroup = sources[group],
|
||||
layout = sourceGroup.layouter,
|
||||
mode = sourceGroup.mode || 'default',
|
||||
layoutCreator: LayoutCreator = layoutMap[layout][mode];
|
||||
layoutCreator: LayoutCreator = layoutMap[layout];
|
||||
|
||||
if (!layout || !layoutCreator) {
|
||||
return;
|
||||
@ -120,13 +119,6 @@ export class ModelConstructor {
|
||||
return this.layoutGroupTable;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
public getLayoutGroupTable(): LayoutGroupTable {
|
||||
return this.layoutGroupTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从源数据构建 node 集
|
||||
@ -430,6 +422,14 @@ export class ModelConstructor {
|
||||
return counter <= 2;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
public getLayoutGroupTable(): LayoutGroupTable {
|
||||
return this.layoutGroupTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁
|
||||
*/
|
||||
|
13
src/RegisteredShape/arrayNode.ts
Normal file
13
src/RegisteredShape/arrayNode.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import G6 from '@antv/g6';
|
||||
|
||||
|
||||
export default G6.registerNode('array-node', {
|
||||
getAnchorPoints() {
|
||||
return [
|
||||
[0.5, 0],
|
||||
[1, 0.5],
|
||||
[0.5, 1],
|
||||
[0, 0.5]
|
||||
];
|
||||
}
|
||||
}, 'rect');
|
@ -16,7 +16,7 @@ export default registerNode('binary-tree-node', {
|
||||
height: height,
|
||||
stroke: cfg.style.stroke || '#333',
|
||||
cursor: cfg.style.cursor,
|
||||
fill: '#eee'
|
||||
fill: cfg.style.backgroundFill || '#eee'
|
||||
},
|
||||
name: 'wrapper'
|
||||
});
|
||||
|
@ -15,7 +15,7 @@ export default registerNode('link-list-node', {
|
||||
width: width,
|
||||
height: height,
|
||||
stroke: cfg.style.stroke || '#333',
|
||||
fill: '#eee',
|
||||
fill: cfg.style.backgroundFill || '#eee',
|
||||
cursor: cfg.style.cursor
|
||||
},
|
||||
name: 'wrapper'
|
||||
|
@ -16,7 +16,7 @@ export default registerNode('tri-tree-node', {
|
||||
height: height,
|
||||
stroke: cfg.style.stroke || '#333',
|
||||
cursor: cfg.style.cursor,
|
||||
fill: '#eee'
|
||||
fill: cfg.style.backgroundFill || '#eee'
|
||||
},
|
||||
name: 'wrapper'
|
||||
});
|
||||
|
@ -16,7 +16,7 @@ export default registerNode('two-cell-node', {
|
||||
width: width,
|
||||
height: height,
|
||||
stroke: cfg.style.stroke,
|
||||
fill: '#eee'
|
||||
fill: cfg.style.backgroundFill || '#eee'
|
||||
},
|
||||
name: 'wrapper'
|
||||
});
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { Engine } from "./engine";
|
||||
import { Bound } from "./Common/boundingRect";
|
||||
import { Group } from "./Common/group";
|
||||
import pointer from "./RegisteredShape/pointer";
|
||||
import G6, { Util } from '@antv/g6';
|
||||
import linkListNode from "./RegisteredShape/linkListNode";
|
||||
import binaryTreeNode from "./RegisteredShape/binaryTreeNode";
|
||||
import Pointer from "./RegisteredShape/pointer";
|
||||
import LinkListNode from "./RegisteredShape/linkListNode";
|
||||
import BinaryTreeNode from "./RegisteredShape/binaryTreeNode";
|
||||
import CLenQueuePointer from "./RegisteredShape/clenQueuePointer";
|
||||
import twoCellNode from "./RegisteredShape/twoCellNode";
|
||||
import TwoCellNode from "./RegisteredShape/twoCellNode";
|
||||
import ArrayNode from "./RegisteredShape/arrayNode";
|
||||
import Cursor from "./RegisteredShape/cursor";
|
||||
import { Vector } from "./Common/vector";
|
||||
import { EngineOptions, LayoutCreator } from "./options";
|
||||
@ -14,7 +15,6 @@ import { SVNode } from "./Model/SVNode";
|
||||
import { SourceNode } from "./sources";
|
||||
|
||||
|
||||
|
||||
export interface StructV {
|
||||
(DOMContainer: HTMLElement, engineOptions: EngineOptions): Engine;
|
||||
Group: typeof Group;
|
||||
@ -25,7 +25,7 @@ export interface StructV {
|
||||
|
||||
registeredShape: any[];
|
||||
|
||||
registeredLayout: { [key: string]: { [key: string]: LayoutCreator } },
|
||||
registeredLayout: { [key: string]: LayoutCreator },
|
||||
|
||||
registerShape: Function,
|
||||
|
||||
@ -50,16 +50,17 @@ SV.G6 = G6;
|
||||
|
||||
SV.registeredLayout = {};
|
||||
SV.registeredShape = [
|
||||
pointer,
|
||||
linkListNode,
|
||||
binaryTreeNode,
|
||||
twoCellNode,
|
||||
Pointer,
|
||||
LinkListNode,
|
||||
BinaryTreeNode,
|
||||
TwoCellNode,
|
||||
Cursor,
|
||||
ArrayNode,
|
||||
CLenQueuePointer,
|
||||
];
|
||||
|
||||
SV.registerShape = G6.registerNode;
|
||||
SV.registerLayout = function(name: string, layoutCreator: LayoutCreator, mode: string = 'default') {
|
||||
SV.registerLayout = function(name: string, layoutCreator: LayoutCreator) {
|
||||
|
||||
if(typeof layoutCreator.sourcesPreprocess !== 'function') {
|
||||
layoutCreator.sourcesPreprocess = function(data: SourceNode[]): SourceNode[] {
|
||||
@ -77,11 +78,7 @@ SV.registerLayout = function(name: string, layoutCreator: LayoutCreator, mode: s
|
||||
return;
|
||||
}
|
||||
|
||||
if(SV.registeredLayout[name] === undefined) {
|
||||
SV.registeredLayout[name] = {};
|
||||
}
|
||||
|
||||
SV.registeredLayout[name][mode] = layoutCreator;
|
||||
SV.registeredLayout[name] = layoutCreator;
|
||||
};
|
||||
|
||||
|
||||
|
@ -25,13 +25,11 @@ export class Reconcile {
|
||||
|
||||
private engine: Engine;
|
||||
private renderer: Renderer;
|
||||
private prevChangeModels: SVModel[];
|
||||
private isFirstPatch: boolean;
|
||||
|
||||
constructor(engine: Engine, renderer: Renderer) {
|
||||
this.engine = engine;
|
||||
this.renderer = renderer;
|
||||
this.prevChangeModels = [];
|
||||
this.isFirstPatch = true;
|
||||
}
|
||||
|
||||
@ -318,10 +316,6 @@ export class Reconcile {
|
||||
* @param models
|
||||
*/
|
||||
private handleChangeModels(models: SVModel[]) {
|
||||
if (models.length === 0) {
|
||||
models = this.prevChangeModels;
|
||||
}
|
||||
|
||||
const changeHighlightColor: string = this.engine.viewOptions.updateHighlight;
|
||||
|
||||
if (!changeHighlightColor || typeof changeHighlightColor !== 'string') {
|
||||
@ -344,8 +338,6 @@ export class Reconcile {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.prevChangeModels = models;
|
||||
}
|
||||
|
||||
|
||||
@ -415,7 +407,5 @@ export class Reconcile {
|
||||
}
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
this.prevChangeModels.length = 0;
|
||||
}
|
||||
public destroy() { }
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { Sources } from "./sources";
|
||||
import { ModelConstructor } from "./Model/modelConstructor";
|
||||
import { AnimationOptions, EngineOptions, InteractionOptions, ViewOptions } from "./options";
|
||||
import { AnimationOptions, EngineOptions, InteractionOptions, LayoutGroupOptions, LayoutOptions, ViewOptions } from "./options";
|
||||
import { EventBus } from "./Common/eventBus";
|
||||
import { ViewContainer } from "./View/viewContainer";
|
||||
import { SVNode } from "./Model/SVNode";
|
||||
@ -50,14 +50,15 @@ export class Engine {
|
||||
/**
|
||||
* 输入数据进行渲染
|
||||
* @param sources
|
||||
* @param force
|
||||
*/
|
||||
public render(source: Sources) {
|
||||
if(source === undefined || source === null) {
|
||||
public render(source: Sources, force: boolean = false) {
|
||||
if (source === undefined || source === null) {
|
||||
return;
|
||||
}
|
||||
``
|
||||
``
|
||||
let stringSource = JSON.stringify(source);
|
||||
if(this.prevStringSource === stringSource) {
|
||||
if (force === false && this.prevStringSource === stringSource) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -71,26 +72,6 @@ export class Engine {
|
||||
this.viewContainer.render(layoutGroupTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换指定数据结构的 mode 主题
|
||||
* @param mode
|
||||
*/
|
||||
public switchMode(layout: string, mode: string) {
|
||||
if(this.prevSource === undefined || this.prevSource === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object.keys(this.prevSource).map(group => {
|
||||
let sourceGroup = this.prevSource[group];
|
||||
|
||||
if(sourceGroup.layouter === layout) {
|
||||
sourceGroup.mode = mode;
|
||||
}
|
||||
});
|
||||
|
||||
this.render(this.prevSource);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 重新布局
|
||||
@ -111,19 +92,19 @@ export class Engine {
|
||||
* @param groupNames
|
||||
*/
|
||||
public hideGroups(groupNames: string | string[]) {
|
||||
const names = Array.isArray(groupNames)? groupNames: [groupNames],
|
||||
const names = Array.isArray(groupNames) ? groupNames : [groupNames],
|
||||
instance = this.viewContainer.getG6Instance(),
|
||||
layoutGroupTable = this.modelConstructor.getLayoutGroupTable();
|
||||
|
||||
layoutGroupTable.forEach(item => {
|
||||
const hasName = names.find(name => name === item.layout);
|
||||
|
||||
if(hasName && !item.isHide) {
|
||||
if (hasName && !item.isHide) {
|
||||
item.modelList.forEach(model => instance.hideItem(model.G6Item));
|
||||
item.isHide = true;
|
||||
}
|
||||
|
||||
if(!hasName && item.isHide) {
|
||||
if (!hasName && item.isHide) {
|
||||
item.modelList.forEach(model => instance.showItem(model.G6Item));
|
||||
item.isHide = false;
|
||||
}
|
||||
@ -140,6 +121,38 @@ export class Engine {
|
||||
return [...modelList, ...accumulateLeakModels];
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据配置变化更新视图
|
||||
* @param modelType
|
||||
* @returns
|
||||
*/
|
||||
public updateStyle(group: string, newOptions: LayoutGroupOptions) {
|
||||
const models = this.getAllModels(),
|
||||
layoutGroup = this.modelConstructor.getLayoutGroupTable().get(group);
|
||||
|
||||
layoutGroup.options = newOptions;
|
||||
models.forEach(item => {
|
||||
if (item.group !== group) {
|
||||
return;
|
||||
}
|
||||
|
||||
const modelType = item.getModelType(),
|
||||
optionsType = layoutGroup.options[modelType];
|
||||
|
||||
if (optionsType) {
|
||||
if (modelType === 'addressLabel') {
|
||||
item.updateG6ModelStyle(item.generateG6ModelProps(optionsType));
|
||||
}
|
||||
else {
|
||||
const targetModelOption = optionsType[item.sourceType];
|
||||
if (targetModelOption) {
|
||||
item.updateG6ModelStyle(item.generateG6ModelProps(targetModelOption));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用id查找某个节点
|
||||
* @param id
|
||||
@ -167,16 +180,16 @@ export class Engine {
|
||||
* @param callback
|
||||
*/
|
||||
public on(eventName: string, callback: Function) {
|
||||
if(typeof callback !== 'function') {
|
||||
if (typeof callback !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
if(eventName === 'onFreed' || eventName === 'onLeak') {
|
||||
if (eventName === 'onFreed' || eventName === 'onLeak') {
|
||||
EventBus.on(eventName, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
if(eventName === 'onLeakAreaUpdate') {
|
||||
if (eventName === 'onLeakAreaUpdate') {
|
||||
EventBus.on(eventName, callback);
|
||||
return;
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ export type Sources = {
|
||||
[key: string]: {
|
||||
data: SourceNode[];
|
||||
layouter: string;
|
||||
mode?: string
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user