--- title: Take Use of State Mechanism order: 5 --- ⚠️ Attention: State with multiple values, mutually exclusive state, updating styles for sub shapes are supported after V3.4. ### Background State of item (Node/Edge) build the fast relationships between 「interactions/data changes」 and 「changes of item styles」. e.g.: the 'hover' state of a node is activated when the mouse enters the node, and the style of the node is changed to response the interaction; 'hover' state is inactivated when the mouse leave the node, and the style of the node is resumed. In actual scene, state has lots of implicity recommand and complexity. ### Challenges - **Configure the target state quickly**: Assign a new state and clear all the existing states on a node; - **State with multiple values**: e.g. the 'bodyState' of a node representing a person has four values 'healthy', 'suspect', 'ill', and 'dead'; - **Mutually exclusive state**: e.g. 'healthy', 'suspect', 'ill', and 'dead' for 'bodyState' are mutually exclusive to each other, any two of them will not exist on a person in the same time; - **Update the styles for all the sub shapes on a node or an edge**: e.g. a node consist of a rect, a text and a icon image. When the state of the node is chagned, styles of all the shapes can be changed to response it; Modify the state configurations: modify the style configurations for a state easily. ### Solution To address the issues above, we have the following functions for states in G6 3.4: - Define a state with unified method; - Set state value with `setItemState` function; - Update state value with `updateItem` function; - Cancel state with `clearItemStates` function. ### Define a State #### Global State The global state in G6 is defined by `nodeStateStyles` and `edgeStateStyles` on the graph instance. ```javascript const graph = new G6.Graph({ container, width, height, nodeStateStyles: { hover: { fill: 'red', 'keyShape-name': { fill: 'red', }, }, }, edgeStateStyles: {}, }); ``` The state style of [keyShape](/en/docs/manual/middle/elements/shape/shape-keyshape/#keyshape) can be defined in `nodeStateStyles` or `edgeStateStyles` directly. You can also define the styles in the object with the key equals to the `name` of the keyShape. #### State for Single Node/Edge Expect set the global styles for items(nodes/edges), you can also define different styles for different items by assgin `stateStyles` in `graph.node(fn)` / `graph.edge(fn)` function. ```javascript graph.node((node) => { return { ...node, stateStyles: {}, }; }); const data = { nodes: [ { id: 'node', stateStyles: {}, }, ], }; ``` #### State Styles for Sub-shapes On the ascpect of drawing, an item(node/edge) has a graphics group, which contains a keyShape and several sub-shapes. Before V3.4, state styles are only available on keyShape, which means users need to define state styles for other sub shapes in `setState` function when custom a node or an item type. G6 3.4 supports state styles for sub shapes. They can also be defined by two ways as [Global State](/#global-state) and State for [Single Node/Edge](/#state-for-single-nodeedge). Now we show how to define the global state styles for sub shapes as an example. ```javascript const graph = new G6.Graph({ container, width, height, nodeStateStyles: { selected: { 'sub-element': { fill: 'green', }, 'text-element': { stroke: 'red', }, }, }, edgeStateStyles: {}, }); ``` In [Global State](/#global-state), we recommand define the keyShape's state styles by an object with key equals to the `name` of the keyShape. Similary, you can define the state styles for any sub shape with an object with key equals to its `name`. As the shown in the above code, we define the state styles for two sub shapes with `name`s `'sub-element'` and `'text-element'` respectively. When we set the state for an item by calling `graph.setItemState(item, 'selected', true)`, the styles of the sub shapes named `'sub-element'` and `'text-element'` will be updated as well. ```javascript // Calling the following code, the styles of sub-element and text-element will be changed graph.setItemState(item, 'selected', true); ``` Besides, G6 also supports `updateItem` function to update the state styles for an item. ⚠️ NOTICE: The state styles for sub-shapes are only available for the sub-shapes which are the chilren of the root graphics group of a node/edge, but not other descendant shapes grouped by nested sub-graphics-groups. The sub-shapes in the built-in nodes/edges are all the children of the root graphics group of a node/edge. If you are customizing a node/edge type, this rule should be noticed. ### Set State G6 V3.4 supports state with multiple values and binary values: > Binary: the value can be `true` or `false`, means the state is activated or inactivated respectivly; Multiple value: e.g. a node represents a person with 'bodyState', which has four values: 'healthy', 'suspect', 'ill', 'dead'. #### Binary State Binary state is commonly used in interactions, e.g. hover, selected, etc. When a node is selected, the selected state is activated with true value; the selected state is inactivated with false when the node is deselected. Set the binary state by calling `graph.setItemState(item, 'selected', true)`. ```javascript const graph = new G6.Graph({ //... nodeStateStyles: { selected: { fill: 'red', }, }, }); graph.setItemState(item, 'selected', true); ``` #### State with Multiple Values State with multiple values exists in complex actual cases, e.g. the 'bodyState' of a node representing a person has four values 'healthy', 'suspect', 'ill', and 'dead'. The binary state can not satisfy such situation. ```javascript const graph = new Graph({ // ... Other configurations // The state styles in different states nodeStateStyles: { // bodyState with multiple values and matually exclusive 'bodyState:healthy': { // the state styles for the keyShape fill: 'green', }, 'bodyState:suspect': {}, 'bodyState:ill': {}, }, }); graph.setItemState(item, 'bodyState', 'healthy'); ``` #### Matually Exclusive State State with multiple values also solves the matually exclusive problem. We now use the same example as above, `bodyState` has four values: `healthy`, `suspect`, `ill`, `dead`. ```javascript // Matually exclusive state graph.setItemState(item, 'bodyState', 'healthy'); // Call the following code, the value of bodyState will be changed to dead, // and item.hasState('bodyState:healthy') will return false graph.setItemState(item, 'bodyState', 'dead'); ``` After calling the code above, the value of the item's `bodyState` is `dead`. ### Update the Configurations for State Styles Before V3.3, G6 does not support modification on the configurations for state styles. And `updateItem` can only be used to update the default style for keyShape. With V3.4, `updateItem` supports updating the default styles and state styles for keyShape and other sub shapes. #### Update Default Styles You can update the default styles for keyShape and sub shapes by assigning the object with the key equals the `name` of the sub shape in `style` of the `updateItem`'s second parameter. ```javascript // Update item with the default style of keyShape and other sub shapes graph.updateItem(item, { style: { // for keyShape's fill, stroke, and opacity fill: 'green', stroke: 'green', opacity: 0.5, // the styles for the sub shape named 'node-text' 'node-text': { stroke: 'yellow', }, }, }); ``` #### Update State Styles `updateItem` also can be used to update the state styles for keyShape and sub shapes with `stateStyles`. ```javascript graph.updateItem(item, { style: { stroke: 'green', 'node-text': { stroke: 'yellow', }, }, stateStyles: { hover: { opacity: 0.1, 'node-text': { stroke: 'blue', }, }, }, }); graph.setItemState(item, 'hover', true); ``` There might be two situations when calling `updateItem`: - The state style to be updated is already activated on an item, `item.hasState('hover') === true`: the style will be changed immediately after calling `updateItem`; - The state style to be updated is not active on an item, `item.hasState('hover') === false`: The style will be changed after calling `graph.setItemState(item, 'hover', true)`. ### Cancel States `graph.clearItemStates` can be used to cancel one or more states set by `graph.setItemState`. ```javascript graph.setItemState(item, 'bodyState', 'healthy'); graph.setItemState(item, 'selected', true); graph.setItemState(item, 'active', true); // Cancel a single state graph.clearItemStates(item, 'selected'); graph.clearItemStates(item, ['selected']); // Cancel multiple states graph.clearItemStates(item, ['bodyState:healthy', 'selected', 'active']); ``` ### State Priority G6 does not explicitly provide the state priority mechanism. But the `hasState` function which is used to get the value of a state, helps users to control the priority by themselves. e.g.: ```javascript // Activate the 'active' state of the item to be true graph.setItemState(item, 'active', true); // returns the value of 'active' state const hasActived = item.hasState('active'); // If the value of 'active' state is false, the 'hover' state can be set to true if (!hasActived) { graph.setItemState(item, 'hover', true); } ```