diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a154c2db96..903dd641434 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,9 @@
# ChangeLog
+#### 3.4.2
+- feat: zoom-canvas behavior support hiding non-keyshape elements when scaling canvas;
+- refactor: when sceond params is null, clearItemStates will clear all states of the item;
+- fix: (changeData bug)[https://github.com/antvis/G6/issues/1323];
+
#### 3.4.1
- feat: force layout clone original data model to allow the customized properties;
- fix: BehaviorOptions type error;
diff --git a/docs/api/Graph.en.md b/docs/api/Graph.en.md
index f0aaf0cd8a8..a778d178685 100644
--- a/docs/api/Graph.en.md
+++ b/docs/api/Graph.en.md
@@ -645,7 +645,7 @@ Clear the states of the item. This function could clear multiple states in the s
| Name | Type | Required | Description |
| ------ | --------------- | -------- | ----------------------------------- |
| item | String / Object | true | The id or the instance of the item. |
-| states | String / Array | null | false | It can be a single state value, an array, or null. When it is null, this operation will clear the **first** state of the item. |
+| states | String / Array | null | false | It can be a single state value, an array, or null. When it is null, this operation will clear all state of the item. |
**Usage**
diff --git a/docs/api/Graph.zh.md b/docs/api/Graph.zh.md
index 6f6097f1776..39b0b84b9f2 100644
--- a/docs/api/Graph.zh.md
+++ b/docs/api/Graph.zh.md
@@ -628,24 +628,27 @@ graph.hideItem(item);
graph.hideItem('nodeId');
```
-### setItemState(item, state, enabled)
+### setItemState(item, state, value)
设置元素状态。
+支持单个状态多值的情况,详情参考 [G6 状态管理最佳实践](https://g6.antv.vision/zh/docs/manual/middle/states/state-new)。
该方法在执行过程中会触发 `beforitemstatechange`,`afteritemstatechange` 事件。
**参数**
| 名称 | 类型 | 是否必选 | 描述 |
-| ------- | --------------- | -------- | ---------------------------------------------------- |
-| item | String / Object | true | 元素 ID 或元素实例 |
+| ------- | --------------- | -------- | ----------- |
+| item | String / Item | true | 元素 ID 或元素实例 |
| state | String | true | 状态值,支持自定义,如 selected、hover、actived 等。 |
-| enabled | Boolean | true | 是否启用状态 |
+| value | Boolean / String | true | 是否启用状态 |
**用法**
```javascript
graph.setItemState('node1', 'selected', true);
+
+graph.setItemState('node1', 'body', 'health');
```
### clearItemStates(item, states)
@@ -657,7 +660,7 @@ graph.setItemState('node1', 'selected', true);
| 名称 | 类型 | 是否必选 | 描述 |
| ------ | --------------- | -------- | ------------------ |
| item | String / Object | true | 元素 ID 或元素实例 |
-| states | String / Array | null | false | 取值可以是单个状态值,也可以是状态值数组或 `null`,当为 `null` 时,清除该元素的**第一个**状态。 |
+| states | String / Array | null | false | 取值可以是单个状态值,也可以是状态值数组 |
**用法**
@@ -668,7 +671,7 @@ graph.clearItemStates(node, 'a');
// 清除多个状态
graph.clearItemStates(node, ['a', 'b']);
-// 清除所有状态
+// 清除所有
graph.clearItemStates(node);
```
diff --git a/docs/manual/introduction.en.md b/docs/manual/introduction.en.md
index 0549659c7ea..af2ed639fef 100644
--- a/docs/manual/introduction.en.md
+++ b/docs/manual/introduction.en.md
@@ -114,9 +114,11 @@ Some implementations combined with front-end libraries from the third party:
## G6 Communication Group
-Users are welcome to join the **G6 Communication Group** (It is a DingTalk group). We are also welcome the github issues.
+Users are welcome to join the **G6 Communication Group** or **G6 Communication Group-2** (It is a DingTalk group). We are also welcome the github issues.
-
+
+
+
## How to Contribute
diff --git a/docs/manual/introduction.zh.md b/docs/manual/introduction.zh.md
index bfaec4fe3e0..dd6ad6225a5 100644
--- a/docs/manual/introduction.zh.md
+++ b/docs/manual/introduction.zh.md
@@ -54,6 +54,7 @@ G6 作为一款专业的图可视化引擎,具有以下特性:
- [G6 核心概念](/zh/docs/manual/middle/graph)
- [G6 高级指引](/zh/docs/manual/advanced/keyconcept/shape-and-properties)
- [API](/zh/docs/api/Graph)
+- [G6 Blog](https://www.yuque.com/antv/g6-blog)
## 快速上手
@@ -106,13 +107,20 @@ graph.render();
- 基于 G6 和 React 的可视化流程编辑器 - Workflow Designer;
- 基于 G6 和 Vue 的可视化编辑器[]();
-- 基于 G6 和 Vue 的可视化图形编辑器 - A visual graph editor based on G6 and Vue。
+- 基于 G6 和 Vue 的可视化图形编辑器 - A visual graph editor based on G6 and Vue;
+- 基于 G6 和 React 实现的 ER 图编辑器;
## G6 图可视化交流群
-欢迎各界 G6 使用者、图可视化爱好者加入 **G6 图可视化交流群**(钉钉群,使用钉钉扫一扫加入)讨论与交流。
+欢迎各界 G6 使用者、图可视化爱好者加入 **G6 图可视化交流群** 及 **G6 图可视化交流二群**(钉钉群,使用钉钉扫一扫加入)讨论与交流。
-
+> **G6 图可视化交流群** 已满员,该群会不定期移除不活跃的成员。
+
+> 由于值班同学的时间和精力有限,**G6 图可视化交流二群** 中的问题我们会不定期回复。欢迎对 G6 感兴趣的同学加入到答疑中来,非常感谢!
+
+
+
+
## 如何贡献
diff --git a/docs/manual/middle/states/defaultBehavior.zh.md b/docs/manual/middle/states/defaultBehavior.zh.md
index 315c326288e..196aaa70477 100644
--- a/docs/manual/middle/states/defaultBehavior.zh.md
+++ b/docs/manual/middle/states/defaultBehavior.zh.md
@@ -50,7 +50,11 @@ const graph = new G6.Graph({
- 含义:缩放画布;
- `type: 'zoom-canvas'`;
-- `sensitivity`:缩放灵敏度,支持 1-10 的数值,默认灵敏度为 5。
+- `sensitivity`:缩放灵敏度,支持 1-10 的数值,默认灵敏度为 5;
+- `minZoom`:最小缩放比例;
+- `maxZoom`:最大缩放比例;
+- `enableOptimize`:是否开启性能优化,默认为 false,设置为 true 开启,开启后缩放比例小于 optimizeZoom 时自动隐藏非 keyShape;
+- `optimizeZoom`:当 enableOptimize 为 true 时起作用,默认值为 0.7,表示当缩放到哪个比例时开始隐藏非 keyShape。
**提示:若要限定缩放尺寸,请在 graph 上设置 `minZoom` 和 `maxZoom`。**
diff --git a/package.json b/package.json
index af2c84053bf..54b1c58191e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@antv/g6",
- "version": "3.4.1",
+ "version": "3.4.2",
"description": "A Graph Visualization Framework in JavaScript",
"keywords": [
"antv",
@@ -50,7 +50,7 @@
"site:deploy": "npm run site:build && gh-pages -d public",
"start": "npm run site:develop",
"test": "jest",
- "test-live": "DEBUG_MODE=1 jest --watch ./tests/unit/layout/dagre-spec.ts",
+ "test-live": "DEBUG_MODE=1 jest --watch ./tests/unit/state/update-element-states-spec.ts",
"lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx",
"watch": "father build -w",
"cdn": "antv-bin upload -n @antv/g6"
diff --git a/site/locale.json b/site/locale.json
index 1a7e5bdbc61..8a29bb8cc29 100644
--- a/site/locale.json
+++ b/site/locale.json
@@ -8,6 +8,7 @@
"更新": "Update",
"感谢信赖": "WE ARE TRUSTED BY",
"专注关系,完备基建": "Dedicated & Complete",
+ "G6·图可视化知多少": "G6 Graph Visualization Blog",
"G6 是一个专注于关系数据的、完备的图可视化引擎": "G6 is a complete graph visualization engine, which focuses on relational data",
"领域深钻,顶尖方案": "Top Solution",
"扎根实际具体业务场景、结合业界领先成果,沉淀顶尖解决方案": "According to practical bussiness scenarios, we found out the top solutions",
diff --git a/site/pages/index.zh.tsx b/site/pages/index.zh.tsx
index 747651f562e..924af64a033 100644
--- a/site/pages/index.zh.tsx
+++ b/site/pages/index.zh.tsx
@@ -121,10 +121,26 @@ const IndexPage = () => {
},
];
+ const insNotifications = [
+ {
+ type: t('推荐'),
+ title: t('欢迎进入 2020 可视化智能研发时代'),
+ date: '2020.01.08',
+ link: 'https://www.yuque.com/antv/blog/ygdubv',
+ },
+ {
+ type: t('推荐'),
+ title: t('G6·图可视化知多少'),
+ date: '2020.03.23',
+ link: 'https://www.yuque.com/antv/g6-blog',
+ },
+ ];
+
return (
<>
this.get('maxZoom') || zoom < this.get('minZoom')) {
return;
}
+
+ const enableOptimize = this.get('enableOptimize')
+ if(enableOptimize) {
+ const optimizeZoom = this.get('optimizeZoom')
+
+ const currentZoom = graph.getZoom()
+ console.log(currentZoom)
+ if(currentZoom < optimizeZoom) {
+ const nodes = graph.getNodes()
+ const edges = graph.getEdges()
+ nodes.map(node => {
+ if(!node.destroyed) {
+ const children = node.getContainer().get('children')
+ children.map(shape => {
+ if(!shape.destoryed && !shape.get('isKeyShape')) {
+ shape.hide()
+ }
+ })
+ }
+ })
+
+ edges.map(edge => {
+ const children = edge.getContainer().get('children')
+ children.map(shape => {
+ if(!shape.get('isKeyShape')) {
+ shape.hide()
+ }
+ })
+ })
+ } else {
+ const nodes = graph.getNodes()
+ const edges = graph.getEdges()
+ nodes.map(node => {
+ const children = node.getContainer().get('children')
+ children.map(shape => {
+ if(!shape.get('visible')) {
+ shape.show()
+ }
+ })
+ })
+
+ edges.map(edge => {
+ const children = edge.getContainer().get('children')
+ children.map(shape => {
+ if(!shape.get('visible')) {
+ shape.show()
+ }
+ })
+ })
+ }
+ }
+
graph.zoom(ratio, { x: point.x, y: point.y });
graph.emit('wheelzoom', e);
},
diff --git a/src/global.ts b/src/global.ts
index ecc8f62ac13..73f58d4c0a4 100644
--- a/src/global.ts
+++ b/src/global.ts
@@ -1,5 +1,5 @@
export default {
- version: '3.4.1',
+ version: '3.4.2',
rootContainerClassName: 'root-container',
nodeContainerClassName: 'node-container',
edgeContainerClassName: 'edge-container',
diff --git a/src/interface/graph.ts b/src/interface/graph.ts
index 8c870bd6291..8e5a2244c36 100644
--- a/src/interface/graph.ts
+++ b/src/interface/graph.ts
@@ -27,6 +27,8 @@ export interface IModeOption {
enableDelegate?: boolean;
maxZoom?: number;
minZoom?: number;
+ enableOptimize?: boolean;
+ optimizeZoom?: number;
multiple?: boolean;
selectedState?: string;
includeEdges?: boolean;
diff --git a/src/item/item.ts b/src/item/item.ts
index 3be3290e8a4..f4fb4001e09 100644
--- a/src/item/item.ts
+++ b/src/item/item.ts
@@ -83,6 +83,7 @@ export default class ItemBase implements IItemBase {
if (!id) {
id = uniqueId(this.get('type'));
+ this.get('model').id = id
}
this.set('id', id);
@@ -375,9 +376,9 @@ export default class ItemBase implements IItemBase {
const model: ModelConfig = self.get('model');
const shape = model.shape || model.type;
if (!states) {
- console.warn(`clearItemStates 参数为空,则不清除任何状态`)
- return;
+ states = originStates
}
+
if (isString(states)) {
states = [states];
}
diff --git a/src/shape/shapeBase.ts b/src/shape/shapeBase.ts
index 125aa60a48e..46a05c94bca 100644
--- a/src/shape/shapeBase.ts
+++ b/src/shape/shapeBase.ts
@@ -324,17 +324,17 @@ export const shapeBase: ShapeOptions = {
const originstyles = {}
deepMix(originstyles, originStyle, filtetDisableStatesStyle, enableStatesStyle)
- for(const key in originstyles) {
- const style = originstyles[key]
+ for(const originKey in originstyles) {
+ const style = originstyles[originKey]
if(isPlainObject(style)) {
- const subShape = group.find(element => element.get('name') === key)
+ const subShape = group.find(element => element.get('name') === originKey)
if(subShape) {
subShape.attr(style)
}
} else {
// 非纯对象,则认为是设置到 keyShape 上面的
shape.attr({
- [key]: style
+ [originKey]: style
})
}
}
diff --git a/stories/Issues/attrs/index.tsx b/stories/Issues/attrs/index.tsx
new file mode 100644
index 00000000000..d7ae7654c68
--- /dev/null
+++ b/stories/Issues/attrs/index.tsx
@@ -0,0 +1,195 @@
+
+import React, { useRef, useEffect } from "react";
+import G6 from '../../../src';
+// import "./styles.css";
+
+// G6.Global.nodeStateStyle.selected = {
+// stroke: "#d9d9d9",
+// fill: "#5394ef"
+// };
+
+G6.registerNode(
+ "sql",
+ {
+ drawShape(cfg, group) {
+ const rect = group.addShape("rect", {
+ attrs: {
+ x: -75,
+ y: -25,
+ width: 168,
+ height: 36,
+ stroke: "#b4afaf", //'#303747',
+ fill: "#b4afaf", //'#303747',
+ lineWidth: 3,
+ radius: [5, 0, 0, 5]
+ },
+ name: "rect-shape"
+ });
+ if (cfg.name) {
+ group.addShape("text", {
+ attrs: {
+ text: cfg.name,
+ x: 0,
+ y: 0,
+ fill: "white",
+ fontSize: 14,
+ textAlign: "center",
+ //textBaseline: 'middle',
+ fontWeight: "bold"
+ },
+ name: "text-shape"
+ });
+ }
+ group.addShape("rect", {
+ attrs: {
+ x: 90,
+ y: -25,
+ width: 36,
+ height: 36,
+ stroke: "#0296EA", //'#303747',
+ fill: "#0296EA", //'#303747',
+ lineWidth: 3,
+ radius: [0, 5, 5, 0]
+ },
+ name: "rect-shape-icon"
+ });
+ group.addShape("rect", {
+ attrs: {
+ x: 98,
+ y: -18,
+ height: 20,
+ width: 20,
+ stroke: "white", //'#303747',
+ fill: "#0296EA", //'#303747',
+ radius: 2
+ },
+ name: "node-state-icon"
+ });
+ group.addShape("text", {
+ attrs: {
+ text: cfg.stateIcon,
+ x: 108,
+ y: 0,
+ fill: "white",
+ fontSize: 14,
+ textAlign: "center",
+ fontWeight: "bold"
+ },
+ name: "icon-text-shape"
+ });
+ return rect;
+ }
+ },
+ "single-node"
+);
+
+export default () => {
+ const graphContainer = useRef(null);
+ let graph = null
+
+ // 图初始化
+ useEffect(() => {
+ if (!graph) {
+ graph = new G6.Graph({
+ container: graphContainer.current,
+ width: 500,
+ height: 500,
+ renderer: "svg",
+ layout: {
+ type: "dagre",
+ nodesepFunc: d => {
+ if (d.id === "3") {
+ return 70;
+ }
+ return 70;
+ },
+ ranksep: 30
+ },
+ defaultNode: {
+ type: "sql",
+ anchorPoints: [[0.5, 0], [0.5, 1]],
+ stateIcon: "+" // 节点中表示状态的icon配置
+ },
+
+ defaultEdge: {
+ type: "cubic-vertical",
+ style: {
+ radius: 20,
+ offset: 45,
+ endArrow: true,
+ lineWidth: 2,
+ stroke: "#C2C8D5"
+ }
+ },
+ modes: {
+ default: ["drag-canvas", "zoom-canvas", "click-select"]
+ },
+ fitView: true
+ });
+ }
+
+
+ const data = {
+ nodes: [
+ {
+ id: "2",
+ dataType: "alps",
+ name: "alps_file2",
+ conf: [
+ {
+ label: "conf",
+ value: "pai_graph.conf"
+ },
+ {
+ label: "dot",
+ value: "pai_graph.dot"
+ },
+ {
+ label: "init",
+ value: "init.rc"
+ }
+ ]
+ }
+ ]
+ };
+
+ graph.data(data);
+ graph.render();
+
+ graph.on('node:click', evt => {
+ let node = evt.item;
+ var child = node.get('group').find(function(item) {
+ return item.get("name") === "icon-text-shape"; //找到图标节点
+ });
+ if(child.attr('text') === '+') {
+ graph.updateItem(node, {
+ style: {
+ 'icon-text-shape': {
+ text: '-'
+ }
+ }
+ })
+ } else {
+ graph.updateItem(node, {
+ style: {
+ 'icon-text-shape': {
+ text: '+'
+ }
+ }
+ })
+ }
+
+
+
+
+ console.log('update text', child.attr('text'))
+ })
+ }, []);
+
+
+ return (
+
+ );
+};
diff --git a/stories/Issues/changeData/data.js b/stories/Issues/changeData/data.js
new file mode 100644
index 00000000000..178b881c629
--- /dev/null
+++ b/stories/Issues/changeData/data.js
@@ -0,0 +1,90 @@
+export const data = {
+ nodes: [
+ {
+ id: "9RQmLGueOikkikLvHVO",
+ label: "Mysql连接账户"
+ },
+ {
+ id: "k79zNA0TkCwQPQWw4yn",
+ label: "ETL数据流"
+ },
+ {
+ id: "GWMF0chbHRKDkENg1hS",
+ label: "ETL数据流2"
+ },
+ {
+ id: "xCzXirgILRm9fF7gjeb",
+ label: "报告"
+ },
+ {
+ id: "I2Msu7qhDMQPmGLOduP",
+ label: "Mysql数据源"
+ },
+ {
+ id: "QUCo43VpL9LaPT4QVx0",
+ label: "Excel数据源"
+ },
+ {
+ id: "GxZeEGkky88xKxq1r22",
+ label: "工厂输出表"
+ },
+ {
+ id: "AoJc4qPcWeOL7NJwOh6",
+ label: "加工输出表"
+ },
+ {
+ id: "cd_638e7750847a4cc78f3cd",
+ label: "图表1"
+ },
+ {
+ id: "cd_8119cb085435454180558",
+ label: "图表2"
+ },
+ {
+ id: "AKl8iaVQamqiMaMCF7E",
+ label: "csv数据源"
+ }
+ ],
+ edges: [
+ {
+ source: "9RQmLGueOikkikLvHVO",
+ target: "I2Msu7qhDMQPmGLOduP"
+ },
+ {
+ source: "k79zNA0TkCwQPQWw4yn",
+ target: "GxZeEGkky88xKxq1r22"
+ },
+ {
+ source: "I2Msu7qhDMQPmGLOduP",
+ target: "k79zNA0TkCwQPQWw4yn"
+ },
+ {
+ source: "QUCo43VpL9LaPT4QVx0",
+ target: "k79zNA0TkCwQPQWw4yn"
+ },
+ {
+ source: "GxZeEGkky88xKxq1r22",
+ target: "xCzXirgILRm9fF7gjeb"
+ },
+ {
+ source: "xCzXirgILRm9fF7gjeb",
+ target: "cd_638e7750847a4cc78f3cd"
+ },
+ {
+ source: "xCzXirgILRm9fF7gjeb",
+ target: "cd_8119cb085435454180558"
+ },
+ {
+ source: "AKl8iaVQamqiMaMCF7E",
+ target: "xCzXirgILRm9fF7gjeb"
+ },
+ {
+ source: "GxZeEGkky88xKxq1r22",
+ target: "GWMF0chbHRKDkENg1hS"
+ },
+ {
+ source: "GWMF0chbHRKDkENg1hS",
+ target: "AoJc4qPcWeOL7NJwOh6"
+ }
+ ]
+};
diff --git a/stories/Issues/changeData/index.tsx b/stories/Issues/changeData/index.tsx
new file mode 100644
index 00000000000..4f8b98720d7
--- /dev/null
+++ b/stories/Issues/changeData/index.tsx
@@ -0,0 +1,123 @@
+import React, { useRef, useEffect } from "react";
+import ReactDOM from "react-dom";
+import { mergeWith } from "lodash";
+import G6 from '../../../src';
+import isArray from "@antv/util/lib/is-array";
+import { data } from "./data";
+// import "./styles.css";
+
+/**
+ * 【问题】!!!
+ * 当我点击“隐藏节点”后,节点正常隐藏
+ * 但是点击“改变数据”调用changeData方法后,节点能隐藏,但是边又显示出来了。
+ */
+export default () => {
+ const graphContainer = useRef(null);
+ let graph = useRef(null);
+
+ // 图初始化
+ useEffect(() => {
+ if (!graph.current) {
+ graph.current = new G6.Graph({
+ container: graphContainer.current,
+ width: 1580,
+ height: 1080,
+ defaultNode: {
+ type: "circle",
+ size: 50,
+ anchorPoints: [[0, 0.5], [1, 0.5]]
+ },
+ defaultEdge: {
+ type: "cubic-horizontal"
+ },
+ layout: {
+ type: "dagre",
+ rankdir: "LR",
+ controlPoints: true
+ },
+ modes: {
+ default: [
+ "drag-canvas",
+ {
+ type: "zoom-canvas",
+ minZoom: 0.5,
+ maxZoom: 2
+ }
+ ]
+ },
+ animate: true
+ });
+ }
+
+ graph.current && graph.current.data(data);
+ graph.current && graph.current.render();
+ }, []);
+
+ /**
+ * 手动合并数据,达到异步加载的效果
+ * @param {*} data 后端返回的新数据
+ */
+ const handleChangeData = data => {
+ const prevData = graph.current && graph.current.save();
+ const newData = mergeWith(prevData, data, (objValue, srcValue) => {
+ if (isArray(objValue)) {
+ return objValue.concat(srcValue);
+ }
+ });
+
+ graph.current && graph.current.changeData(newData);
+ };
+
+ /**
+ * 模拟点击加载数据
+ * 模拟点击AoJc4qPcWeOL7NJwOh6[加工输出表]节点后,后端返回异步加载的数据
+ */
+ const handleLoadData = () => {
+ const mockData = {
+ nodes: [
+ {
+ id: "vm1234",
+ label: "新增报告"
+ }
+ ],
+ edges: [
+ {
+ source: "AoJc4qPcWeOL7NJwOh6",
+ target: "vm1234"
+ }
+ ]
+ };
+ handleChangeData(mockData);
+ };
+
+ /**
+ * 递归隐藏节点和边
+ */
+ const collapsePrev = node => {
+ const edges = node.getInEdges();
+ edges.forEach(edge => {
+ edge.hide();
+ const sourceNode = edge.getSource();
+ if (sourceNode.getOutEdges().length === 1) {
+ sourceNode.hide();
+ collapsePrev(sourceNode);
+ }
+ });
+ };
+
+ /**
+ * 模拟折叠GxZeEGkky88xKxq1r22[工厂输出表]节点
+ */
+ const handleHideNode = () => {
+ const node = graph.current.findById("GxZeEGkky88xKxq1r22");
+ collapsePrev(node);
+ };
+
+ return (
+
+ );
+};
diff --git a/stories/Issues/issues.stories.tsx b/stories/Issues/issues.stories.tsx
index 9a6caf1b794..d7a05637fe7 100644
--- a/stories/Issues/issues.stories.tsx
+++ b/stories/Issues/issues.stories.tsx
@@ -2,6 +2,8 @@ import { storiesOf } from '@storybook/react';
import React from 'react';
import DragCanvas from './component/drag-canvas';
import DagreArrow from './component/dagre-arrow';
+import ChageData from './changeData'
+import ChangeAttr from './attrs'
export default { title: 'Issues' };
@@ -11,4 +13,10 @@ storiesOf('Issues', module)
))
.add('dagre polyline arrow', () => (
-));
+))
+.add('change data', () => (
+
+))
+.add('change attr', () => (
+
+))
diff --git a/tests/unit/behavior/zoom-spec.ts b/tests/unit/behavior/zoom-spec.ts
index 318f4d63312..f2890d820c2 100644
--- a/tests/unit/behavior/zoom-spec.ts
+++ b/tests/unit/behavior/zoom-spec.ts
@@ -124,4 +124,77 @@ describe('zoom-canvas', () => {
expect(matrix[6]).toEqual(10);
expect(matrix[7]).toEqual(10);
});
+
+ it('zoom with optimize', () => {
+ const graph = new Graph({
+ container: div,
+ width: 500,
+ height: 500,
+ modes: {
+ default: [{
+ type: 'zoom-canvas',
+ enableOptimize: true
+ }]
+ },
+ });
+
+ let e = createWheelEvent(graph.get('canvas').get('el'), 100, 100, 100);
+ graph.emit('wheel', e);
+ let matrix = graph.get('group').getMatrix();
+ console.log(matrix)
+ expect(approximateEqual(matrix[0], 1.1)).toBe(true);
+ expect(approximateEqual(matrix[4], 1.1)).toBe(true);
+ expect(approximateEqual(matrix[6], -10)).toBe(true);
+ expect(approximateEqual(matrix[7], -10)).toBe(true);
+
+ const data = {
+ nodes: [
+ {
+ id: 'node1',
+ x: 100,
+ y: 100,
+ label: 'label'
+ },
+ {
+ id: 'node2',
+ x: 100,
+ y: 200,
+ label: 'label2'
+ }
+ ],
+ edges: [
+ {
+ source: 'node1',
+ target: 'node2',
+ label: 'edge'
+ }
+ ]
+ }
+
+ graph.data(data)
+ graph.render()
+
+ // 默认 zoom=1,会显示所有元素
+ let node1 = graph.findById('node1')
+ let container = node1.getContainer()
+ container.get('children').map(child => {
+ expect(child.get('visible')).toBe(true)
+ })
+
+ graph.zoom(0.5)
+ e = createWheelEvent(graph.get('canvas').get('el'), 100, 100, 100);
+ graph.emit('wheel', e);
+
+ // 只显示 keyShape
+ node1 = graph.findById('node1')
+ container = node1.getContainer()
+ expect(node1.getKeyShape().get('visible')).toBe(true)
+ container.get('children').map(child => {
+ if(!child.get('isKeyShape')) {
+ expect(child.get('visible')).toBe(false)
+ }
+ })
+
+ graph.destroy()
+ })
});
diff --git a/tests/unit/graph/graph-spec.ts b/tests/unit/graph/graph-spec.ts
index d26f6822d65..b25f344ca38 100644
--- a/tests/unit/graph/graph-spec.ts
+++ b/tests/unit/graph/graph-spec.ts
@@ -837,7 +837,7 @@ describe('all node link center', () => {
expect(graph.findAllByState('node', 'b').length).toBe(0);
});
- it.only('default node & edge style', () => {
+ it('default node & edge style', () => {
const defaultGraph = new Graph({
container: div,
width: 500,
@@ -1158,9 +1158,9 @@ describe('mapper fn', () => {
graph.setItemState(node, 'custom', true);
expect(keyShape.attr('green'));
+ // clear all states of the item
graph.clearItemStates(node);
- // green
- expect(keyShape.attr('fill')).toEqual('green');
+ expect(keyShape.attr('fill')).toEqual('#666');
const edge = graph.addItem('edge', { id: 'edge2', source: 'node', target: 'node2Mapped' });
diff --git a/tests/unit/state/update-element-states-spec.ts b/tests/unit/state/update-element-states-spec.ts
index 24f6cdc5d76..27f8c18044f 100644
--- a/tests/unit/state/update-element-states-spec.ts
+++ b/tests/unit/state/update-element-states-spec.ts
@@ -54,6 +54,64 @@ G6.registerNode('self-node', {
describe('update', () => {
+ it('without second params, clear all states', () => {
+ const graph = new G6.Graph({
+ container: div,
+ width: 500,
+ height: 500,
+ nodeStateStyles: {
+ hover: {
+ opacity: 0.3
+ },
+ 'body:health': {
+ fill: 'red'
+ }
+ },
+ defaultNode: {
+ size: 25,
+ style: {
+ fill: 'steelblue',
+ opacity: 1
+ }
+ },
+ });
+ const data = {
+ nodes: [
+ {
+ id: 'node1',
+ x: 100,
+ y: 100,
+ },
+ {
+ id: 'node2',
+ x: 200,
+ y: 100,
+ },
+ ],
+ };
+ graph.data(data);
+ graph.render();
+
+ const item = graph.findById('node1')
+ graph.setItemState(item, 'hover', true)
+ expect(item.hasState('hover')).toBe(true)
+
+ const keyShape = item.getKeyShape()
+ expect(keyShape.attr('fill')).toEqual('steelblue')
+
+ graph.setItemState(item, 'body', 'health')
+
+ expect(item.getStates().length).toBe(2)
+ expect(item.hasState('body:health')).toBe(true)
+ expect(item.getKeyShape().attr('fill')).toEqual('red')
+
+ graph.clearItemStates(item)
+ expect(item.hasState('hover')).toBe(false)
+ expect(item.hasState('body:health')).toBe(false)
+ expect(item.getStates().length).toBe(0)
+
+ graph.destroy()
+ })
it('setItemState, then updateItem', () => {
const graph = new G6.Graph({
container: div,