From 93973b80dc5c52c8c75cffc081fe1b2ec8fd62b9 Mon Sep 17 00:00:00 2001 From: Yanyan-Wang Date: Wed, 11 Nov 2020 15:28:43 +0800 Subject: [PATCH] feat: basic style(light version) for edges and combos --- examples/item/defaultCombos/demo/circle.js | 59 ++++++++------- examples/item/defaultCombos/demo/rect.js | 62 +++++++++------- gatsby-browser.js | 4 +- src/global.ts | 84 +++++++++++++++++++--- src/item/combo.ts | 2 +- src/item/item.ts | 7 +- src/shape/combo.ts | 17 +++++ src/shape/combos/circle.ts | 7 +- src/shape/combos/rect.ts | 9 ++- src/shape/edge.ts | 20 ++++++ src/shape/edges/polyline.ts | 7 ++ src/util/color.ts | 30 +++++++- tests/unit/graph/controller/state-spec.ts | 2 +- tests/unit/graph/graph-spec.ts | 4 +- tests/unit/graph/svg-spec.ts | 2 +- tests/unit/shape/edge-spec.ts | 5 +- tests/unit/state/edge-state-spec.ts | 1 + 17 files changed, 244 insertions(+), 78 deletions(-) diff --git a/examples/item/defaultCombos/demo/circle.js b/examples/item/defaultCombos/demo/circle.js index 74e39fbb8d..f83077f591 100644 --- a/examples/item/defaultCombos/demo/circle.js +++ b/examples/item/defaultCombos/demo/circle.js @@ -33,34 +33,34 @@ const graph = new G6.Graph({ fitCenter: true, // Set groupByTypes to false to get rendering result with reasonable visual zIndex for combos groupByTypes: false, - defaultCombo: { - type: 'circle', - style: { - lineWidth: 1, - }, - labelCfg: { - refY: 10, - position: 'top', - style: { - fontSize: 18, - }, - }, - }, modes: { default: ['drag-canvas', 'drag-node', 'drag-combo', 'collapse-expand-combo'], }, - comboStateStyles: { - // the style configurations for the hover state on the combo - hover: { - lineWidth: 3, - }, - }, - nodeStateStyles: { - // the hover configurations for the hover state on the node - hover: { - lineWidth: 3, + defaultCombo: { + type: 'circle', + /* style for the keyShape */ + // style: { + // lineWidth: 1, + // }, + labelCfg: { + /* label's offset to the keyShape */ + // refY: 10, + /* label's position, options: center, top, bottom, left, right */ + position: 'top', + /* label's style */ + // style: { + // fontSize: 18, + // }, }, }, + /* styles for different states, there are built-in styles for states: active, inactive, selected, highlight, disable */ + /* you can extend it or override it as you want */ + // comboStateStyles: { + // active: { + // fill: '#f00', + // opacity: 0.5 + // }, + // }, }); graph.data(data); @@ -68,10 +68,19 @@ graph.render(); graph.on('combo:mouseenter', (evt) => { const { item } = evt; - graph.setItemState(item, 'hover', true); + graph.setItemState(item, 'active', true); }); graph.on('combo:mouseleave', (evt) => { const { item } = evt; - graph.setItemState(item, 'hover', false); + graph.setItemState(item, 'active', false); +}); +graph.on('combo:click', (evt) => { + const { item } = evt; + graph.setItemState(item, 'selected', true); +}); +graph.on('canvas:click', (evt) => { + graph.getCombos().forEach(combo => { + graph.clearItemStates(combo); + }); }); diff --git a/examples/item/defaultCombos/demo/rect.js b/examples/item/defaultCombos/demo/rect.js index 14666d3496..3529aca0a0 100644 --- a/examples/item/defaultCombos/demo/rect.js +++ b/examples/item/defaultCombos/demo/rect.js @@ -33,35 +33,36 @@ const graph = new G6.Graph({ fitCenter: true, // Set groupByTypes to false to get rendering result with reasonable visual zIndex for combos groupByTypes: false, - defaultCombo: { - type: 'rect', - size: [50, 50], // Combo 的最小大小 - style: { - lineWidth: 1, - }, - labelCfg: { - refY: 10, - position: 'top', - style: { - fontSize: 18, - }, - }, - }, modes: { default: ['drag-canvas', 'drag-node', 'drag-combo', 'collapse-expand-combo'], }, - comboStateStyles: { - // the style configurations for the hover state on the combo - hover: { - lineWidth: 3, - }, - }, - nodeStateStyles: { - // the hover configurations for the hover state on the node - hover: { - lineWidth: 3, + defaultCombo: { + type: 'rect', + /* The minimum size of the combo. combo 最小大小 */ + size: [50, 50], + /* style for the keyShape */ + // style: { + // lineWidth: 1, + // }, + labelCfg: { + /* label's offset to the keyShape */ + // refY: 10, + /* label's position, options: center, top, bottom, left, right */ + position: 'top', + /* label's style */ + // style: { + // fontSize: 18, + // }, }, }, + /* styles for different states, there are built-in styles for states: active, inactive, selected, highlight, disable */ + /* you can extend it or override it as you want */ + // comboStateStyles: { + // active: { + // fill: '#f00', + // opacity: 0.5 + // }, + // }, }); graph.data(data); @@ -69,10 +70,19 @@ graph.render(); graph.on('combo:mouseenter', (evt) => { const { item } = evt; - graph.setItemState(item, 'hover', true); + graph.setItemState(item, 'active', true); }); graph.on('combo:mouseleave', (evt) => { const { item } = evt; - graph.setItemState(item, 'hover', false); + graph.setItemState(item, 'active', false); +}); +graph.on('combo:click', (evt) => { + const { item } = evt; + graph.setItemState(item, 'selected', true); +}); +graph.on('canvas:click', (evt) => { + graph.getCombos().forEach(combo => { + graph.clearItemStates(combo); + }); }); diff --git a/gatsby-browser.js b/gatsby-browser.js index d314bea4b2..de19224340 100644 --- a/gatsby-browser.js +++ b/gatsby-browser.js @@ -1,4 +1,4 @@ -// window.g6 = require('./src/index.ts'); // import the source for debugging -window.g6 = require('./dist/g6.min.js'); // import the package for webworker +window.g6 = require('./src/index.ts'); // import the source for debugging +// window.g6 = require('./dist/g6.min.js'); // import the package for webworker window.insertCss = require('insert-css'); window.Chart = require('@antv/chart-node-g6'); diff --git a/src/global.ts b/src/global.ts index ad22bb6b5a..a6f19a4d8c 100644 --- a/src/global.ts +++ b/src/global.ts @@ -72,9 +72,6 @@ export default { fill: colorSet.inactiveFill, stroke: colorSet.inactiveStroke, lineWidth: 1, - 'text-shape': { - fontWeight: 500 - } }, disable: { fill: colorSet.disableFill, @@ -87,21 +84,55 @@ export default { fill: textColor, textAlign: 'center', textBaseline: 'middle', + fontSize: 12, }, }, defaultEdge: { type: 'line', style: { - stroke: disableColor, + stroke: colorSet.edgeMainStroke, + lineAppendWidth: 4, }, size: 1, - color: disableColor, + color: colorSet.edgeMainStroke, + }, + // 边应用状态后的样式,默认仅提供 active、selected、highlight、inactive、disable,用户可以自己扩展 + edgeStateStyles: { + active: { + stroke: colorSet.edgeActiveStroke, + lineWidth: 1, + }, + selected: { + stroke: colorSet.edgeSelectedStroke, + lineWidth: 2, + shadowColor: colorSet.edgeSelectedStroke, + shadowBlur: 10, + 'text-shape': { + fontWeight: 500 + }, + }, + highlight: { + stroke: colorSet.edgeHighlightStroke, + lineWidth: 2, + 'text-shape': { + fontWeight: 500 + } + }, + inactive: { + stroke: colorSet.edgeInactiveStroke, + lineWidth: 1, + }, + disable: { + stroke: colorSet.edgeDisableStroke, + lineWidth: 1, + }, }, comboLabel: { style: { fill: textColor, // textAlign: 'center', textBaseline: 'middle', + fontSize: 12, }, refY: 10, // Combo 的默认文本不居中时的偏移量 refX: 10, // Combo 的默认文本不居中时的偏移量 @@ -109,18 +140,53 @@ export default { defaultCombo: { type: 'circle', style: { - fill: '#F3F9FF', + fill: colorSet.comboMainFill, lineWidth: 1, - stroke: '#A3B1BF', - opacity: 0.8, + stroke: colorSet.comboMainStroke, r: 5, width: 20, height: 10, }, size: [20, 5], - color: '#A3B1BF', + color: colorSet.comboMainStroke, padding: [25, 20, 15, 20], }, + // combo 应用状态后的样式,默认仅提供 active、selected、highlight、inactive、disable,用户可以自己扩展 + comboStateStyles: { + active: { + stroke: colorSet.comboActiveStroke, + lineWidth: 1, + fill: colorSet.comboActiveFill, + }, + selected: { + stroke: colorSet.comboSelectedStroke, + lineWidth: 2, + fill: colorSet.comboSelectedFill, + shadowColor: colorSet.comboSelectedStroke, + shadowBlur: 10, + 'text-shape': { + fontWeight: 500 + }, + }, + highlight: { + stroke: colorSet.comboHighlightStroke, + lineWidth: 2, + fill: colorSet.comboHighlightFill, + 'text-shape': { + fontWeight: 500 + } + }, + inactive: { + stroke: colorSet.comboInactiveStroke, + fill: colorSet.comboInactiveFill, + lineWidth: 1, + }, + disable: { + stroke: colorSet.comboDisableStroke, + fill: colorSet.comboDisableFill, + lineWidth: 1, + }, + }, delegateStyle: { fill: '#F3F9FF', fillOpacity: 0.5, diff --git a/src/item/combo.ts b/src/item/combo.ts index 8c4c145ace..d91e0db527 100644 --- a/src/item/combo.ts +++ b/src/item/combo.ts @@ -24,7 +24,7 @@ export default class Combo extends Node implements ICombo { public getShapeCfg(model: ComboConfig): ComboConfig { const styles = this.get('styles'); const bbox = this.get('bbox'); - if (styles) { + if (styles && bbox) { // merge graph的item样式与数据模型中的样式 const newModel = model; const size = { diff --git a/src/item/item.ts b/src/item/item.ts index 801a9168a9..8b2f28061c 100644 --- a/src/item/item.ts +++ b/src/item/item.ts @@ -101,8 +101,10 @@ export default class ItemBase implements IItemBase { const model = this.get('model'); let { id } = model; + const itemType = this.get('type'); + if (!id) { - id = uniqueId(this.get('type')); + id = uniqueId(itemType); this.get('model').id = id; } @@ -117,7 +119,7 @@ export default class ItemBase implements IItemBase { this.init(); this.draw(); - const shapeType = (model.shape as string) || (model.type as string) || 'circle'; + const shapeType = (model.shape as string) || (model.type as string) || (itemType === 'edge' ? 'line' : 'circle'); const shapeFactory = this.get('shapeFactory'); if (shapeFactory && shapeFactory[shapeType]) { const { options } = shapeFactory[shapeType]; @@ -384,7 +386,6 @@ export default class ItemBase implements IItemBase { public setState(state: string, value: string | boolean) { const states: string[] = this.get('states'); const shapeFactory = this.get('shapeFactory'); - // debugger let stateName = state; let filterStateName = state; if (isString(value)) { diff --git a/src/shape/combo.ts b/src/shape/combo.ts index a387907cb2..a717ca908e 100644 --- a/src/shape/combo.ts +++ b/src/shape/combo.ts @@ -27,6 +27,23 @@ const singleCombo: ShapeOptions = { */ refX: Global.comboLabel.refX, refY: Global.comboLabel.refY, + + options: { + style: { + stroke: Global.defaultCombo.style.stroke, + fill: Global.defaultCombo.style.fill, + lineWidth: Global.defaultCombo.style.lineWidth + }, + labelCfg: { + style: { + fill: Global.comboLabel.style.fill, + fontSize: Global.comboLabel.style.fontSize, + }, + }, + stateStyles: { + ...Global.comboStateStyles + } + }, /** * 获取 Combo 宽高 * @internal 返回 Combo 的大小,以 [width, height] 的方式维护 diff --git a/src/shape/combos/circle.ts b/src/shape/combos/circle.ts index f177a85e55..cf34ddd175 100644 --- a/src/shape/combos/circle.ts +++ b/src/shape/combos/circle.ts @@ -19,15 +19,18 @@ Shape.registerCombo( stroke: Global.defaultCombo.style.stroke, fill: Global.defaultCombo.style.fill, lineWidth: Global.defaultCombo.style.lineWidth, - opacity: 0.8, }, labelCfg: { style: { - fill: '#595959', + fill: Global.comboLabel.style.fill, + fontSize: Global.comboLabel.style.fontSize, }, refX: 0, refY: 0, }, + stateStyles: { + ...Global.comboStateStyles + } }, shapeType: 'circle', // 文本位置 diff --git a/src/shape/combos/rect.ts b/src/shape/combos/rect.ts index 4c65f12ae2..64f041a9dd 100644 --- a/src/shape/combos/rect.ts +++ b/src/shape/combos/rect.ts @@ -18,13 +18,13 @@ Shape.registerCombo( radius: 0, stroke: Global.defaultCombo.style.stroke, fill: Global.defaultCombo.style.fill, - lineWidth: Global.defaultCombo.style.lineWidth, - fillOpacity: 1, + lineWidth: Global.defaultCombo.style.lineWidth }, // 文本样式配置 labelCfg: { style: { - fill: '#595959', + fill: Global.comboLabel.style.fill, + fontSize: Global.comboLabel.style.fontSize, }, }, // 连接点,默认为左右 @@ -32,6 +32,9 @@ Shape.registerCombo( [0, 0.5], [1, 0.5], ], + stateStyles: { + ...Global.comboStateStyles + } }, shapeType: 'rect', labelPosition: 'top', diff --git a/src/shape/edge.ts b/src/shape/edge.ts index fd3c54b920..bf55c4d886 100644 --- a/src/shape/edge.ts +++ b/src/shape/edge.ts @@ -55,6 +55,26 @@ const singleEdge: ShapeOptions = { * @type {Boolean} */ labelAutoRotate: false, + + // 自定义边时的配置 + options: { + size: Global.defaultEdge.size, + style: { + x: 0, + y: 0, + stroke: Global.defaultEdge.style.stroke, + lineWidth: Global.defaultEdge.style.lineWidth + }, + labelCfg: { + style: { + fill: Global.edgeLabel.style.fill, + fontSize: Global.edgeLabel.style.fontSize, + }, + }, + stateStyles: { + ...Global.edgeStateStyles + } + }, /** * 获取边的 path * @internal 供扩展的边覆盖 diff --git a/src/shape/edges/polyline.ts b/src/shape/edges/polyline.ts index da24944d7f..3d01e038cc 100644 --- a/src/shape/edges/polyline.ts +++ b/src/shape/edges/polyline.ts @@ -15,16 +15,20 @@ Shape.registerEdge( { options: { color: Global.defaultEdge.color, + size: Global.defaultEdge.size, style: { radius: 0, offset: 15, x: 0, y: 0, + stroke: Global.defaultEdge.style.stroke, + lineWidth: Global.defaultEdge.style.lineWidth }, // 文本样式配置 labelCfg: { style: { fill: Global.edgeLabel.style.fill, + fontSize: Global.edgeLabel.style.fontSize, }, }, routeCfg: { @@ -33,6 +37,9 @@ Shape.registerEdge( maximumLoops: 1000, gridSize: 10, // 指定精度 }, + stateStyles: { + ...Global.edgeStateStyles + } }, shapeType: 'polyline', // 文本位置 diff --git a/src/util/color.ts b/src/util/color.ts index 7449d1596f..9450d5d801 100644 --- a/src/util/color.ts +++ b/src/util/color.ts @@ -41,6 +41,34 @@ export const getColorsWithSubjectColor = (subjectColor, backColor = '#fff', disa highlightFill: mixColor(backColor, subjectColor, 0.2).rgb().toString(), disableStroke: mixColor(backColor, disableColor, 0.3).rgb().toString(), - disableFill: mixColor(backColor, disableColor, 0.05).rgb().toString() + disableFill: mixColor(backColor, disableColor, 0.05).rgb().toString(), + + + edgeMainStroke: disableColor, + edgeActiveStroke: subjectColor, + edgeInactiveStroke: mixColor(backColor, disableColor, 0.2).rgb().toString(), + edgeSelectedStroke: subjectColor, + edgeHighlightStroke: subjectColor, + edgeDisableStroke: mixColor(backColor, disableColor, 0.1).rgb().toString(), + + + comboMainStroke: mixColor(backColor, disableColor, 0.3).rgb().toString(), + comboMainFill: mixColor(backColor, disableColor, 0.02).rgb().toString(), + + comboActiveStroke: subjectColor, + comboActiveFill: lightSubject, + + comboInactiveStroke: mixColor(backColor, disableColor, 0.3).rgb().toString(), + comboInactiveFill: mixColor(backColor, disableColor, 0.02).rgb().toString(), + + comboSelectedStroke: subjectColor, + comboSelectedFill: mixColor(backColor, disableColor, 0.02).rgb().toString(), + + comboHighlightStroke: 'rgb(53, 119, 222)', // TODO: how to generate it ??? + comboHighlightFill: mixColor(backColor, disableColor, 0.02).rgb().toString(), + + comboDisableStroke: mixColor(backColor, disableColor, 0.2).rgb().toString(), + comboDisableFill: mixColor(backColor, disableColor, 0.05).rgb().toString(), + } } \ No newline at end of file diff --git a/tests/unit/graph/controller/state-spec.ts b/tests/unit/graph/controller/state-spec.ts index d268902d63..d8d4e5a481 100644 --- a/tests/unit/graph/controller/state-spec.ts +++ b/tests/unit/graph/controller/state-spec.ts @@ -51,7 +51,7 @@ describe('graph state controller', () => { setTimeout(() => { expect(graphCount).toBe(1); done(); - }, 16); + }, 100); }); it('state with activate-relations', done => { diff --git a/tests/unit/graph/graph-spec.ts b/tests/unit/graph/graph-spec.ts index 9cc68f60c6..68b7a030c0 100644 --- a/tests/unit/graph/graph-spec.ts +++ b/tests/unit/graph/graph-spec.ts @@ -1208,12 +1208,12 @@ describe('mapper fn', () => { expect(keyShape.attr('fillOpacity')).toEqual(1); graph.setItemState(edge, 'selected', true); - expect(keyShape.attr('stroke')).toEqual('rgb(150, 150, 150)'); + expect(keyShape.attr('stroke')).toEqual('rgb(95, 149, 255)'); expect(keyShape.attr('lineWidth')).toEqual(2); expect(keyShape.attr('fillOpacity')).toEqual(1); graph.setItemState(edge, 'custom', true); - expect(keyShape.attr('stroke')).toEqual('rgb(150, 150, 150)'); + expect(keyShape.attr('stroke')).toEqual('rgb(95, 149, 255)'); expect(keyShape.attr('lineWidth')).toEqual(2); expect(keyShape.attr('opacity')).toEqual(0.5); }); diff --git a/tests/unit/graph/svg-spec.ts b/tests/unit/graph/svg-spec.ts index 77f6c15880..cef0ac2a51 100644 --- a/tests/unit/graph/svg-spec.ts +++ b/tests/unit/graph/svg-spec.ts @@ -1290,7 +1290,7 @@ describe('behaviors', () => { expect(unrelativeNodeKeyShape.attr('opacity')).toBe(0.1); const unrelativeEdge = graph.getEdges()[1]; const unrelativeEdgeKeyShape = unrelativeEdge.get('group').get('children')[0]; - expect(unrelativeEdgeKeyShape.attr('stroke')).toBe('rgb(150, 150, 150)'); + expect(unrelativeEdgeKeyShape.attr('stroke')).toBe('rgb(234, 234, 234)'); expect(unrelativeEdgeKeyShape.attr('opacity')).toBe(0.1); graph.emit('node:mouseleave', { item }); diff --git a/tests/unit/shape/edge-spec.ts b/tests/unit/shape/edge-spec.ts index e86b13f574..c9e28488cd 100644 --- a/tests/unit/shape/edge-spec.ts +++ b/tests/unit/shape/edge-spec.ts @@ -523,12 +523,13 @@ describe('shape edge test', () => { const edge = graph.getEdges()[0]; const path = edge.get('group').get('children')[0]; let bbox = path.getBBox(); - expect(bbox.minX).toEqual(91.60845891791658); + console.log(bbox); + expect(bbox.minX).toEqual(89.60845891791658); graph.emit('node:dragstart', { x: 100, y: 100, item: node }); graph.emit('node:drag', { x: 200, y: 200, item: node }); graph.emit('node:dragend', { x: 200, y: 200, item: node }); bbox = path.getBBox(); - expect(bbox.minX).toEqual(191.6084589179166); + expect(bbox.minX).toEqual(189.6084589179166); }); it('clear', () => { diff --git a/tests/unit/state/edge-state-spec.ts b/tests/unit/state/edge-state-spec.ts index 6497438a23..aa706d35ec 100644 --- a/tests/unit/state/edge-state-spec.ts +++ b/tests/unit/state/edge-state-spec.ts @@ -141,6 +141,7 @@ describe('graph edge states', () => { shadowBlur: 10, shadowOffsetX: 10, shadowOffsetY: 20, + lineWidth: 10 }, }, defaultEdge: {