Konva 中的动画线位置
Animating Line position in Konva
我有一个网络,我想用 Konva(和 react-konva 绑定)绘制。当位置更新时,我想将网络中的节点动画化到它们的新位置,同时还动画化连接它们的 link 的开始和结束位置。
我从以下简单示例开始,但似乎无法让线条以与节点相同的方式进行动画处理。
有没有办法解决这个问题,还是我处理方法不对?
import React from "react";
import { Stage, Layer, Rect, Line } from "react-konva";
class Node extends React.Component {
componentDidUpdate() {
this.rect.to({
x: this.props.x,
y: this.props.y,
});
}
render() {
const { id } = this.props;
const color = id === "a" ? "blue" : "red";
return (
<Rect
ref={node => {
this.rect = node;
}}
width={5}
height={5}
fill={color}
/>
);
}
}
class Link extends React.Component {
componentDidUpdate() {
const x0 = 0;
const y0 = 0;
const x1 = 100;
const y1 = 100;
this.line.to({
x: x0,
y: y0,
points: [x1, y1, x0, y0],
});
}
render() {
const color = "#ccc";
return (
<Line
ref={node => {
this.line = node;
}}
stroke={color}
/>
);
}
}
class Graph extends React.Component {
constructor(props) {
super(props);
this.state = {
nodes: [{ id: "a", x: 0, y: 0 }, { id: "b", x: 200, y: 200 }],
links: [
{
source: "a",
target: "b",
},
],
};
}
handleClick = () => {
const nodes = this.state.nodes.map(node => {
const position = node.x === 0 ? { x: 200, y: 200 } : { x: 0, y: 0 };
return Object.assign({}, node, position);
});
this.setState({
nodes,
});
};
render() {
const { links, nodes } = this.state;
return (
<React.Fragment>
<Stage width={800} height={800}>
<Layer>
{nodes.map((node, index) => {
return (
<Node
key={`node-${index}`}
x={node.x}
y={node.y}
id={node.id}
/>
);
})}
</Layer>
<Layer>
{links.map(link => {
return (
<Link
source={nodes.find(node => node.id === link.source)}
target={nodes.find(node => node.id === link.target)}
/>
);
})}
</Layer>
</Stage>
<button onClick={this.handleClick}>Click me</button>
</React.Fragment>
);
}
}
export default Graph;
您可能需要为 points
属性设置初始值以获得更好的补间效果。
此外,您没有在 Link
组件中使用 source
和 target
。你应该使用那个道具来计算动画。
import React from "react";
import { render } from "react-dom";
import { Stage, Layer, Rect, Line } from "react-konva";
class Node extends React.Component {
componentDidMount() {
this.rect.setAttrs({
x: this.props.x,
y: this.props.y
});
}
componentDidUpdate() {
this.rect.to({
x: this.props.x,
y: this.props.y
});
}
render() {
const { id } = this.props;
const color = id === "a" ? "blue" : "red";
return (
<Rect
ref={node => {
this.rect = node;
}}
width={5}
height={5}
fill={color}
/>
);
}
}
class Link extends React.Component {
componentDidMount() {
// set initial value:
const { source, target } = this.props;
console.log(source, target);
this.line.setAttrs({
points: [source.x, source.y, target.x, target.y]
});
}
componentDidUpdate() {
this.animate();
}
animate() {
const { source, target } = this.props;
this.line.to({
points: [source.x, source.y, target.x, target.y]
});
}
render() {
const color = "#ccc";
return (
<Line
ref={node => {
this.line = node;
}}
stroke={color}
/>
);
}
}
class Graph extends React.Component {
constructor(props) {
super(props);
this.state = {
nodes: [{ id: "a", x: 0, y: 0 }, { id: "b", x: 200, y: 200 }],
links: [
{
source: "a",
target: "b"
}
]
};
}
handleClick = () => {
const nodes = this.state.nodes.map(node => {
const position = node.x === 0 ? { x: 200, y: 200 } : { x: 0, y: 0 };
return Object.assign({}, node, position);
});
this.setState({
nodes
});
};
render() {
const { links, nodes } = this.state;
return (
<React.Fragment>
<Stage width={800} height={300}>
<Layer>
{nodes.map((node, index) => {
return (
<Node
key={`node-${index}`}
x={node.x}
y={node.y}
id={node.id}
/>
);
})}
</Layer>
<Layer>
{links.map(link => {
return (
<Link
source={nodes.find(node => node.id === link.source)}
target={nodes.find(node => node.id === link.target)}
/>
);
})}
</Layer>
</Stage>
<button onClick={this.handleClick}>Click me</button>
</React.Fragment>
);
}
}
render(<Graph />, document.getElementById("root"));
演示:https://codesandbox.io/s/react-konva-animating-line-demo-erufn
我有一个网络,我想用 Konva(和 react-konva 绑定)绘制。当位置更新时,我想将网络中的节点动画化到它们的新位置,同时还动画化连接它们的 link 的开始和结束位置。
我从以下简单示例开始,但似乎无法让线条以与节点相同的方式进行动画处理。
有没有办法解决这个问题,还是我处理方法不对?
import React from "react";
import { Stage, Layer, Rect, Line } from "react-konva";
class Node extends React.Component {
componentDidUpdate() {
this.rect.to({
x: this.props.x,
y: this.props.y,
});
}
render() {
const { id } = this.props;
const color = id === "a" ? "blue" : "red";
return (
<Rect
ref={node => {
this.rect = node;
}}
width={5}
height={5}
fill={color}
/>
);
}
}
class Link extends React.Component {
componentDidUpdate() {
const x0 = 0;
const y0 = 0;
const x1 = 100;
const y1 = 100;
this.line.to({
x: x0,
y: y0,
points: [x1, y1, x0, y0],
});
}
render() {
const color = "#ccc";
return (
<Line
ref={node => {
this.line = node;
}}
stroke={color}
/>
);
}
}
class Graph extends React.Component {
constructor(props) {
super(props);
this.state = {
nodes: [{ id: "a", x: 0, y: 0 }, { id: "b", x: 200, y: 200 }],
links: [
{
source: "a",
target: "b",
},
],
};
}
handleClick = () => {
const nodes = this.state.nodes.map(node => {
const position = node.x === 0 ? { x: 200, y: 200 } : { x: 0, y: 0 };
return Object.assign({}, node, position);
});
this.setState({
nodes,
});
};
render() {
const { links, nodes } = this.state;
return (
<React.Fragment>
<Stage width={800} height={800}>
<Layer>
{nodes.map((node, index) => {
return (
<Node
key={`node-${index}`}
x={node.x}
y={node.y}
id={node.id}
/>
);
})}
</Layer>
<Layer>
{links.map(link => {
return (
<Link
source={nodes.find(node => node.id === link.source)}
target={nodes.find(node => node.id === link.target)}
/>
);
})}
</Layer>
</Stage>
<button onClick={this.handleClick}>Click me</button>
</React.Fragment>
);
}
}
export default Graph;
您可能需要为 points
属性设置初始值以获得更好的补间效果。
此外,您没有在 Link
组件中使用 source
和 target
。你应该使用那个道具来计算动画。
import React from "react";
import { render } from "react-dom";
import { Stage, Layer, Rect, Line } from "react-konva";
class Node extends React.Component {
componentDidMount() {
this.rect.setAttrs({
x: this.props.x,
y: this.props.y
});
}
componentDidUpdate() {
this.rect.to({
x: this.props.x,
y: this.props.y
});
}
render() {
const { id } = this.props;
const color = id === "a" ? "blue" : "red";
return (
<Rect
ref={node => {
this.rect = node;
}}
width={5}
height={5}
fill={color}
/>
);
}
}
class Link extends React.Component {
componentDidMount() {
// set initial value:
const { source, target } = this.props;
console.log(source, target);
this.line.setAttrs({
points: [source.x, source.y, target.x, target.y]
});
}
componentDidUpdate() {
this.animate();
}
animate() {
const { source, target } = this.props;
this.line.to({
points: [source.x, source.y, target.x, target.y]
});
}
render() {
const color = "#ccc";
return (
<Line
ref={node => {
this.line = node;
}}
stroke={color}
/>
);
}
}
class Graph extends React.Component {
constructor(props) {
super(props);
this.state = {
nodes: [{ id: "a", x: 0, y: 0 }, { id: "b", x: 200, y: 200 }],
links: [
{
source: "a",
target: "b"
}
]
};
}
handleClick = () => {
const nodes = this.state.nodes.map(node => {
const position = node.x === 0 ? { x: 200, y: 200 } : { x: 0, y: 0 };
return Object.assign({}, node, position);
});
this.setState({
nodes
});
};
render() {
const { links, nodes } = this.state;
return (
<React.Fragment>
<Stage width={800} height={300}>
<Layer>
{nodes.map((node, index) => {
return (
<Node
key={`node-${index}`}
x={node.x}
y={node.y}
id={node.id}
/>
);
})}
</Layer>
<Layer>
{links.map(link => {
return (
<Link
source={nodes.find(node => node.id === link.source)}
target={nodes.find(node => node.id === link.target)}
/>
);
})}
</Layer>
</Stage>
<button onClick={this.handleClick}>Click me</button>
</React.Fragment>
);
}
}
render(<Graph />, document.getElementById("root"));
演示:https://codesandbox.io/s/react-konva-animating-line-demo-erufn