fix: 新增可以修改整体样式的接口

This commit is contained in:
黎智洲 2021-12-15 19:51:41 +08:00
parent e1a69b5e91
commit 3626a6eb19
18 changed files with 166 additions and 188 deletions

View File

@ -6,7 +6,7 @@ SV.registerLayout('Array', {
sourcesPreprocess(sources) { sourcesPreprocess(sources) {
const firstElement = sources[0]; const firstElement = sources[0];
if(firstElement.external) { if (firstElement.external) {
firstElement.headExternal = firstElement.external; firstElement.headExternal = firstElement.external;
delete firstElement.external; delete firstElement.external;
} }
@ -18,7 +18,7 @@ SV.registerLayout('Array', {
return { return {
node: { node: {
default: { default: {
type: 'rect', type: 'array-node',
label: '[id]', label: '[id]',
size: [60, 30], size: [60, 30],
labelOptions: { labelOptions: {
@ -56,77 +56,13 @@ SV.registerLayout('Array', {
layout(elements) { layout(elements) {
let arr = 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]; let width = arr[i].get('size')[0];
if(i > 0) { if (i > 0) {
arr[i].set('x', arr[i - 1].get('x') + width); 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');

View File

@ -100,27 +100,8 @@
let data = [{ let data = [{
PTree: {
data: [
{
id: '1001',
data: 'A',
parent: -1,
index: 0
},
{
id: '1002',
data: 'B',
parent: 0,
index: 1
},
],
layouter: 'PTree'
}
}, {
Array: { 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' layouter: 'Array'
} }
}, { }, {
@ -172,7 +153,7 @@
}); });
document.getElementById('switch-mode').addEventListener('click', e => { document.getElementById('switch-mode').addEventListener('click', e => {
cur.switchMode('Array', 'colorful'); cur.updateStyle('Array', newArrayOption);
}); });
const leak = document.getElementById('leak'); const leak = document.getElementById('leak');

40
dist/sv.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,8 +1,10 @@
{ {
"dependencies": { "dependencies": {
"@antv/g6": "^4.4.1" "@antv/g6": "^4.4.1",
"merge": "^2.1.1"
}, },
"devDependencies": { "devDependencies": {
"merge": "^2.1.1",
"ts-loader": "^5.2.1", "ts-loader": "^5.2.1",
"typescript": "^3.2.2", "typescript": "^3.2.2",
"webpack": "^4.46.0", "webpack": "^4.46.0",

View File

@ -24,8 +24,7 @@ export class SVLink extends SVModel {
this.G6ModelProps = this.generateG6ModelProps(options); this.G6ModelProps = this.generateG6ModelProps(options);
} }
generateG6ModelProps(options: LinkOption): EdgeConfig {
protected generateG6ModelProps(options: LinkOption): EdgeConfig {
let sourceAnchor = options.sourceAnchor, let sourceAnchor = options.sourceAnchor,
targetAnchor = options.targetAnchor; targetAnchor = options.targetAnchor;

View File

@ -3,7 +3,7 @@ import { Style } from "../options";
import { BoundingRect } from "../Common/boundingRect"; import { BoundingRect } from "../Common/boundingRect";
import { EdgeConfig, Item, NodeConfig } from "@antv/g6-core"; import { EdgeConfig, Item, NodeConfig } from "@antv/g6-core";
import { Graph } from "_@antv_g6-pc@0.5.0@@antv/g6-pc"; 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 * G6 model
* @param option * @param option
*/ */
protected generateG6ModelProps(options: unknown) { generateG6ModelProps(options: unknown): NodeConfig | EdgeConfig {
return null; return null;
} }
@ -87,7 +87,7 @@ export class SVModel {
} }
if (attr === 'style' || attr === 'labelCfg') { if (attr === 'style' || attr === 'labelCfg') {
Object.assign(this.G6ModelProps[attr], value); this.G6ModelProps[attr] = merge(this.G6ModelProps[attr] || {}, value);
} }
else { else {
this.G6ModelProps[attr] = value; 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 * @returns

View File

@ -51,7 +51,7 @@ export class SVNode extends SVModel {
this.G6ModelProps = this.generateG6ModelProps(options); this.G6ModelProps = this.generateG6ModelProps(options);
} }
protected generateG6ModelProps(options: NodeOption): NodeConfig { generateG6ModelProps(options: NodeOption): NodeConfig {
const style = Util.objectClone<Style>(options.style); const style = Util.objectClone<Style>(options.style);
return { return {

View File

@ -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 { Util } from "../Common/util";
import { AddressLabelOption, IndexLabelOption, MarkerOption, NodeLabelOption, Style } from "../options"; import { AddressLabelOption, IndexLabelOption, MarkerOption, NodeLabelOption, Style } from "../options";
import { SourceNode } from "../sources";
import { SVModel } from "./SVModel"; import { SVModel } from "./SVModel";
import { SVNode } from "./SVNode"; import { SVNode } from "./SVNode";
@ -108,7 +107,7 @@ export class SVIndexLabel extends SVNodeAppendage {
this.G6ModelProps = this.generateG6ModelProps(options) as NodeConfig; this.G6ModelProps = this.generateG6ModelProps(options) as NodeConfig;
} }
generateG6ModelProps(options: IndexLabelOption) { generateG6ModelProps(options: IndexLabelOption): NodeConfig | EdgeConfig {
return { return {
id: this.id, id: this.id,
x: 0, x: 0,
@ -155,7 +154,7 @@ export class SVMarker extends SVNodeAppendage {
this.G6ModelProps = this.generateG6ModelProps(options); this.G6ModelProps = this.generateG6ModelProps(options);
} }
protected generateG6ModelProps(options: MarkerOption): NodeConfig { generateG6ModelProps(options: MarkerOption): NodeConfig {
this.anchor = options.anchor; this.anchor = options.anchor;
const type = options.type, const type = options.type,

View File

@ -44,13 +44,12 @@ export class ModelConstructor {
*/ */
public construct(sources: Sources): LayoutGroupTable { public construct(sources: Sources): LayoutGroupTable {
const layoutGroupTable = new Map<string, LayoutGroup>(), 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 => { Object.keys(sources).forEach(group => {
let sourceGroup = sources[group], let sourceGroup = sources[group],
layout = sourceGroup.layouter, layout = sourceGroup.layouter,
mode = sourceGroup.mode || 'default', layoutCreator: LayoutCreator = layoutMap[layout];
layoutCreator: LayoutCreator = layoutMap[layout][mode];
if (!layout || !layoutCreator) { if (!layout || !layoutCreator) {
return; return;
@ -120,13 +119,6 @@ export class ModelConstructor {
return this.layoutGroupTable; return this.layoutGroupTable;
} }
/**
*
* @returns
*/
public getLayoutGroupTable(): LayoutGroupTable {
return this.layoutGroupTable;
}
/** /**
* node * node
@ -430,6 +422,14 @@ export class ModelConstructor {
return counter <= 2; return counter <= 2;
} }
/**
*
* @returns
*/
public getLayoutGroupTable(): LayoutGroupTable {
return this.layoutGroupTable;
}
/** /**
* *
*/ */

View 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');

View File

@ -16,7 +16,7 @@ export default registerNode('binary-tree-node', {
height: height, height: height,
stroke: cfg.style.stroke || '#333', stroke: cfg.style.stroke || '#333',
cursor: cfg.style.cursor, cursor: cfg.style.cursor,
fill: '#eee' fill: cfg.style.backgroundFill || '#eee'
}, },
name: 'wrapper' name: 'wrapper'
}); });

View File

@ -15,7 +15,7 @@ export default registerNode('link-list-node', {
width: width, width: width,
height: height, height: height,
stroke: cfg.style.stroke || '#333', stroke: cfg.style.stroke || '#333',
fill: '#eee', fill: cfg.style.backgroundFill || '#eee',
cursor: cfg.style.cursor cursor: cfg.style.cursor
}, },
name: 'wrapper' name: 'wrapper'

View File

@ -16,7 +16,7 @@ export default registerNode('tri-tree-node', {
height: height, height: height,
stroke: cfg.style.stroke || '#333', stroke: cfg.style.stroke || '#333',
cursor: cfg.style.cursor, cursor: cfg.style.cursor,
fill: '#eee' fill: cfg.style.backgroundFill || '#eee'
}, },
name: 'wrapper' name: 'wrapper'
}); });

View File

@ -16,7 +16,7 @@ export default registerNode('two-cell-node', {
width: width, width: width,
height: height, height: height,
stroke: cfg.style.stroke, stroke: cfg.style.stroke,
fill: '#eee' fill: cfg.style.backgroundFill || '#eee'
}, },
name: 'wrapper' name: 'wrapper'
}); });

View File

@ -1,12 +1,13 @@
import { Engine } from "./engine"; import { Engine } from "./engine";
import { Bound } from "./Common/boundingRect"; import { Bound } from "./Common/boundingRect";
import { Group } from "./Common/group"; import { Group } from "./Common/group";
import pointer from "./RegisteredShape/pointer";
import G6, { Util } from '@antv/g6'; import G6, { Util } from '@antv/g6';
import linkListNode from "./RegisteredShape/linkListNode"; import Pointer from "./RegisteredShape/pointer";
import binaryTreeNode from "./RegisteredShape/binaryTreeNode"; import LinkListNode from "./RegisteredShape/linkListNode";
import BinaryTreeNode from "./RegisteredShape/binaryTreeNode";
import CLenQueuePointer from "./RegisteredShape/clenQueuePointer"; 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 Cursor from "./RegisteredShape/cursor";
import { Vector } from "./Common/vector"; import { Vector } from "./Common/vector";
import { EngineOptions, LayoutCreator } from "./options"; import { EngineOptions, LayoutCreator } from "./options";
@ -14,7 +15,6 @@ import { SVNode } from "./Model/SVNode";
import { SourceNode } from "./sources"; import { SourceNode } from "./sources";
export interface StructV { export interface StructV {
(DOMContainer: HTMLElement, engineOptions: EngineOptions): Engine; (DOMContainer: HTMLElement, engineOptions: EngineOptions): Engine;
Group: typeof Group; Group: typeof Group;
@ -25,7 +25,7 @@ export interface StructV {
registeredShape: any[]; registeredShape: any[];
registeredLayout: { [key: string]: { [key: string]: LayoutCreator } }, registeredLayout: { [key: string]: LayoutCreator },
registerShape: Function, registerShape: Function,
@ -50,16 +50,17 @@ SV.G6 = G6;
SV.registeredLayout = {}; SV.registeredLayout = {};
SV.registeredShape = [ SV.registeredShape = [
pointer, Pointer,
linkListNode, LinkListNode,
binaryTreeNode, BinaryTreeNode,
twoCellNode, TwoCellNode,
Cursor, Cursor,
ArrayNode,
CLenQueuePointer, CLenQueuePointer,
]; ];
SV.registerShape = G6.registerNode; 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') { if(typeof layoutCreator.sourcesPreprocess !== 'function') {
layoutCreator.sourcesPreprocess = function(data: SourceNode[]): SourceNode[] { layoutCreator.sourcesPreprocess = function(data: SourceNode[]): SourceNode[] {
@ -77,11 +78,7 @@ SV.registerLayout = function(name: string, layoutCreator: LayoutCreator, mode: s
return; return;
} }
if(SV.registeredLayout[name] === undefined) { SV.registeredLayout[name] = layoutCreator;
SV.registeredLayout[name] = {};
}
SV.registeredLayout[name][mode] = layoutCreator;
}; };

View File

@ -25,13 +25,11 @@ export class Reconcile {
private engine: Engine; private engine: Engine;
private renderer: Renderer; private renderer: Renderer;
private prevChangeModels: SVModel[];
private isFirstPatch: boolean; private isFirstPatch: boolean;
constructor(engine: Engine, renderer: Renderer) { constructor(engine: Engine, renderer: Renderer) {
this.engine = engine; this.engine = engine;
this.renderer = renderer; this.renderer = renderer;
this.prevChangeModels = [];
this.isFirstPatch = true; this.isFirstPatch = true;
} }
@ -318,10 +316,6 @@ export class Reconcile {
* @param models * @param models
*/ */
private handleChangeModels(models: SVModel[]) { private handleChangeModels(models: SVModel[]) {
if (models.length === 0) {
models = this.prevChangeModels;
}
const changeHighlightColor: string = this.engine.viewOptions.updateHighlight; const changeHighlightColor: string = this.engine.viewOptions.updateHighlight;
if (!changeHighlightColor || typeof changeHighlightColor !== 'string') { if (!changeHighlightColor || typeof changeHighlightColor !== 'string') {
@ -344,8 +338,6 @@ export class Reconcile {
}); });
} }
}); });
this.prevChangeModels = models;
} }
@ -415,7 +407,5 @@ export class Reconcile {
} }
} }
public destroy() { public destroy() { }
this.prevChangeModels.length = 0;
}
} }

View File

@ -1,6 +1,6 @@
import { Sources } from "./sources"; import { Sources } from "./sources";
import { ModelConstructor } from "./Model/modelConstructor"; 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 { EventBus } from "./Common/eventBus";
import { ViewContainer } from "./View/viewContainer"; import { ViewContainer } from "./View/viewContainer";
import { SVNode } from "./Model/SVNode"; import { SVNode } from "./Model/SVNode";
@ -50,14 +50,15 @@ export class Engine {
/** /**
* *
* @param sources * @param sources
* @param force
*/ */
public render(source: Sources) { public render(source: Sources, force: boolean = false) {
if(source === undefined || source === null) { if (source === undefined || source === null) {
return; return;
} }
`` ``
let stringSource = JSON.stringify(source); let stringSource = JSON.stringify(source);
if(this.prevStringSource === stringSource) { if (force === false && this.prevStringSource === stringSource) {
return; return;
} }
@ -71,26 +72,6 @@ export class Engine {
this.viewContainer.render(layoutGroupTable); 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 * @param groupNames
*/ */
public hideGroups(groupNames: string | string[]) { public hideGroups(groupNames: string | string[]) {
const names = Array.isArray(groupNames)? groupNames: [groupNames], const names = Array.isArray(groupNames) ? groupNames : [groupNames],
instance = this.viewContainer.getG6Instance(), instance = this.viewContainer.getG6Instance(),
layoutGroupTable = this.modelConstructor.getLayoutGroupTable(); layoutGroupTable = this.modelConstructor.getLayoutGroupTable();
layoutGroupTable.forEach(item => { layoutGroupTable.forEach(item => {
const hasName = names.find(name => name === item.layout); 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.modelList.forEach(model => instance.hideItem(model.G6Item));
item.isHide = true; item.isHide = true;
} }
if(!hasName && item.isHide) { if (!hasName && item.isHide) {
item.modelList.forEach(model => instance.showItem(model.G6Item)); item.modelList.forEach(model => instance.showItem(model.G6Item));
item.isHide = false; item.isHide = false;
} }
@ -140,6 +121,38 @@ export class Engine {
return [...modelList, ...accumulateLeakModels]; 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查找某个节点 * 使id查找某个节点
* @param id * @param id
@ -167,16 +180,16 @@ export class Engine {
* @param callback * @param callback
*/ */
public on(eventName: string, callback: Function) { public on(eventName: string, callback: Function) {
if(typeof callback !== 'function') { if (typeof callback !== 'function') {
return; return;
} }
if(eventName === 'onFreed' || eventName === 'onLeak') { if (eventName === 'onFreed' || eventName === 'onLeak') {
EventBus.on(eventName, callback); EventBus.on(eventName, callback);
return; return;
} }
if(eventName === 'onLeakAreaUpdate') { if (eventName === 'onLeakAreaUpdate') {
EventBus.on(eventName, callback); EventBus.on(eventName, callback);
return; return;
} }

View File

@ -19,7 +19,6 @@ export type Sources = {
[key: string]: { [key: string]: {
data: SourceNode[]; data: SourceNode[];
layouter: string; layouter: string;
mode?: string
} }
}; };