前端学习】AntV G6-09 复杂定制的侧面、侧面动画
最编程
2024-10-19 07:15:48
...
课程视频
AntV G6:复杂的自定义边、边动画(上)_哔哩哔哩_bilibili
AntV G6:复杂的自定义边、边动画(下)_哔哩哔哩_bilibili
讲义截图
提及链接
https://codesandbox.io/p/sandbox/register-polyline-getpath-jkd6dn
G6
实例讲解
(从第一个课程链接的04:10开始)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>07 复杂的自定义边、边动画</title>
<!-- 引入 G6 -->
<script src="https://gw.alipayobjects.com/os/lib/antv/g6/4.3.11/dist/g6.min.js"></script>
<!-- <script src="https://gw.alipayobjects.com/os/lib/antv/g6/3.7.1/dist/g6.min.js"></script> -->
</head>
<body>
<div id="container"></div>
<script>
const { getLabelPosition, transform } = G6.Util;
const addAnimateArrow = (path, group, arrowStyle) => {
const arrow =
group.find((ele) => ele.get("name") === "animate-arrow") ||
group.addShape("marker", {
attrs: {
stroke: "#3370ff",
fill: "#fff",
...arrowStyle,
x: 16,
y: 0,
r: 8,
lineWidth: 2,
symbol: (x, y, r) => {
return [
["M", x - 8, y - 8],
["L", x - 2, y],
["L", x - 8, y + 8]
];
}
},
name: "animate-arrow"
});
arrow.stopAnimate();
// animation for the red circle
arrow.animate(
(ratio) => {
// the operations in each frame. Ratio ranges from 0 to 1 indicating the prograss of the animation. Returns the modified configurations
// get the position on the edge according to the ratio
const tmpPoint = path.getPoint(ratio);
const roundPoint = {
x: Math.round(tmpPoint.x),
y: Math.round(tmpPoint.y)
};
const pos = getLabelPosition(path, ratio);
let matrix = [1, 0, 0, 0, 1, 0, 0, 0, 1];
matrix = transform(matrix, [
["t", -roundPoint.x, -roundPoint.y],
["r", pos.angle],
["t", roundPoint.x, roundPoint.y]
]);
// returns the modified configurations here, x and y here
return {
x: tmpPoint.x,
y: tmpPoint.y,
matrix
};
},
{
repeat: true, // Whether executes the animation repeatly
duration: 3000 // the duration for executing once
}
);
};
const lineDashAnimate = (path) => {
const lineDash = [6, 4, 2, 4];
path.stopAnimate();
let index = 0;
// Define the animation
path.animate(
() => {
index++;
if (index > 9) {
index = 0;
}
const res = {
lineDash,
lineDashOffset: -index
};
// returns the modified configurations here, lineDash and lineDashOffset here
return res;
},
{
repeat: true, // whether executes the animation repeatly
duration: 3000 // the duration for executing once
}
);
};
G6.registerEdge(
"line-arrow",
{
getPath(points) {
const startPoint = points[0];
const endPoint = points[1];
return [
["M", startPoint.x, startPoint.y],
["L", endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y],
["L", endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y],
["L", endPoint.x, endPoint.y]
];
},
afterDraw(cfg, group) {
const keyShape = group.find((ele) => ele.get("name") === "edge-shape");
const attrs = keyShape.attr();
const halo = group.addShape("path", {
attrs: {
...attrs,
lineWidth: 8,
opacity: 0.2
},
name: "edge-halo"
});
halo.hide();
const { endLabel, endPoint, labelCfg } = cfg;
const { style: labelStyle = {}, refX = 0, refY = 0 } = labelCfg;
if (endLabel) {
const endLabelShape = group.addShape("text", {
attrs: {
text: endLabel,
x: endPoint.x - refX,
y: endPoint.y + refY,
textAlign: "right",
fill: "#000",
textBaseline: "middle",
...labelStyle
},
name: "end-label-shape"
});
console.log("endLabelShape", endLabelShape);
}
},
afterUpdate(cfg, item) {
const group = item.getContainer();
const endLabelShape = group.find(
(ele) => ele.get("name") === "end-label-shape"
);
const { endLabel, endPoint, labelCfg } = cfg;
const { style: labelStyle = {}, refX = 0, refY = 0 } = labelCfg;
endLabelShape.attr({
text: endLabel,
x: endPoint.x - refX,
y: endPoint.y + refY,
...labelStyle
});
},
setState(name, value, item) {
const group = item.getContainer();
const keyShapePath = group.find(
(ele) => ele.get("name") === "edge-shape"
);
switch (name) {
case "hover":
const halo = group.find((ele) => ele.get("name") === "edge-halo");
if (value) {
const path = keyShapePath.attr("path");
halo.show();
halo.attr("path", path);
} else {
halo.hide();
}
break;
case "selected":
if (value) {
lineDashAnimate(keyShapePath);
// addAnimateArrow(keyShapePath, group, keyShapePath.attr());
} else {
keyShapePath.stopAnimate();
keyShapePath.attr("lineDash", undefined);
// const arrow = group.find(ele => ele.get('name') === 'animate-arrow');
// if (arrow) arrow.remove(true);
}
break;
default:
break;
}
}
},
"polyline"
);
const data = {
nodes: [
{
id: "7",
x: 150,
y: 100
},
{
id: "8",
x: 300,
y: 200
}
],
edges: [
{
source: "7",
target: "8",
label: "xxx",
endLabel: "yyy"
}
]
};
const container = document.getElementById("container");
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
const graph = new G6.Graph({
container: "container",
width,
height,
// translate the graph to align the canvas's center, support by v3.5.1
fitCenter: true,
modes: {
// behavior
default: ["drag-node", "drag-canvas", "click-select"]
},
defaultNode: {
type: "circle",
size: 40,
anchorPoints: [
[0, 0.5],
[1, 0.5]
],
style: {
fill: "#DEE9FF",
stroke: "#5B8FF9"
},
linkPoints: {
left: true,
right: true,
fill: "#fff",
stroke: "#1890FF",
size: 5
}
},
defaultEdge: {
type: "line-arrow",
color: "#F6BD16",
labelCfg: {
autoRotate: true,
position: "start",
refX: 10
}
}
});
graph.data(data);
graph.render();
graph.on("edge:mouseenter", (e) => {
graph.setItemState(e.item, "hover", true);
});
graph.on("edge:mouseleave", (e) => {
graph.setItemState(e.item, "hover", false);
});
const clearEdgeStates = () => {
const selectedEdges = graph.findAllByState("selected");
selectedEdges?.forEach((edge) => graph.setItemState(edge, "selected", false));
};
graph.on("node:click", (e) => {
clearEdgeStates();
const relatedEdges = e.item.getEdges();
relatedEdges.forEach((edge) => graph.setItemState(edge, "selected", true));
});
graph.on("canvas:click", (e) => clearEdgeStates());
if (typeof window !== "undefined")
window.onresize = () => {
if (!graph || graph.get("destroyed")) return;
if (!container || !container.scrollWidth || !container.scrollHeight) return;
graph.changeSize(container.scrollWidth, container.scrollHeight);
};
</script>
</body>
</html>