react + d3.js + TS 日轮图 类型优化
1. 结构
interface IDatum {
name: string;
popularity? number;
children?: this[];
}
2. 类型优化
2.1 d3.partiion<>()
let root: d3.HierarchyRectangularNode<IDatum> = d3.partition<IDatum>().size([ 2 * Math.PI, height / 1.6 ])(
d3
.hierarchy<IDatum>(data)
.sum((d: IDatum) => d.popularity || 0)
.sort(
(a: d3.HierarchyNode<IDatum>, b: d3.HierarchyNode<IDatum>) => (b.daa.popularity || 0) - (a.data.popularity || 0)
)
)
2.2 d3.arc<>()
const arc = d3
.arc<d3.HierarchyRectangularNode<IDatum>>()
.innerRadius((d: d3.HierarchyRectangularNode<IDatum>) => d.y0)
.outerRadius((d: d3.HierarchyRectangularNode<IDatum>) => d.y1)
.startAngle((d: d3.HierarchyRectanguleNode<IDatum>) => d.x0)
.endAngle((d: d3.HierarchyRectanggularNode<IDatum>)=> d.x1)
.padRadius(Math.PI / 2)
.padRadius((d: d3.HierarchyNode<IDatum>) =>
Math.min((d.x1 - d.x0) / 2, 0.005)
)
2.3 selection.attr()
g.selectAll('.datatext')
.data(root.descendants().filter((d: any) => d.depth !== 0))
.join("text")
.attr("class", "datatext")
.attr("text-anchor", "middle")
.attr("pointer-events", "none")
.attr("font-size", (d: d3.HierarchyRectangularNode<IDatum>) => d.data.name.length < 15 ? "1em" : ".85em")
.attr("transform", (d: d3.HierarchyRectangularNode<IDatum>)=>{
const x = (((d.x0 + d.x1) / 2) * 180 ) / Math.PI;
const y = (d.y0 + d.y1) / 2;
return `rotate(${x - 90} translate(${y}, 0)) rotate(${ x < 180 ? 0 : 180}) translate(0, 5)`;
})
.text((d: d3.HierarchyRectangularNode<IDatum>) => d.data.name);
3. 代码
import React, { useState, useRef, useEffect } from "react";
import * as d3 from "d3";
interface IGamesDatum {
name: string;
popularity: number;
}
interface IDatum {
name: string;
popularity?: number;
children?: this[];
}
const SunBurst: React.FC = () => {
const [width] = useState(1600);
const [height] = useState(940);
const [margin] = useState({
left: 150,
top: 60,
right: 50,
bottom: 50,
});
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
const svg = useRef<SVGSVGElement>(null);
useEffect(() => {
let root: d3.HierarchyRectangularNode<IDatum>;
const svgSelection = d3.select(svg.current);
svgSelection.attr("width", width).attr("height", height);
const g = svgSelection
.append("g")
.attr("transform", `translate(${width / 2}, ${height / 2})`);
let color: any;
const fill = (d: any) => {
// if (d.depth === 0) return color(d.data.name);
while (d.depth > 1) d = d.parent;
return color(d.data.name);
};
const arc = d3
.arc<d3.HierarchyRectangularNode<IDatum>>()
// .innerRadius((d: any) => {
// return d.y0;
// })
.innerRadius((d: d3.HierarchyRectangularNode<IDatum>) => d.y0)
.outerRadius((d: d3.HierarchyRectangularNode<IDatum>) => d.y1)
.startAngle((d: d3.HierarchyRectangularNode<IDatum>) => d.x0)
.endAngle((d: d3.HierarchyRectangularNode<IDatum>) => d.x1)
.padRadius(Math.PI / 2)
.padAngle((d: d3.HierarchyRectangularNode<IDatum>) =>
Math.min((d.x1 - d.x0) / 2, 0.005)
);
const render = (data: any) => {
color = d3.scaleOrdinal(d3.schemeCategory10);
g.selectAll(".datapath")
.data<d3.HierarchyRectangularNode<IDatum>>(
data.descendants().filter((d: any) => d.depth !== 0)
)
.join("path")
.attr("class", "datapath")
.attr("fill", fill)
.attr("d", arc);
g.selectAll(".datatext")
.data(root.descendants().filter((d: any) => d.depth !== 0))
.join("text")
.attr("class", "datatext")
.attr("text-anchor", "middle")
.attr("pointer-events", "none")
.attr("font-size", (d: d3.HierarchyRectangularNode<IDatum>) =>
d.data.name.length < 15 ? "1em" : ".85em"
)
.attr("transform", (d: d3.HierarchyRectangularNode<IDatum>) => {
const x = (((d.x0 + d.x1) / 2) * 180) / Math.PI;
const y = (d.y0 + d.y1) / 2;
//
return `rotate(${x - 90}) translate(${y}, 0) rotate(${
x < 180 ? 0 : 180
}) translate(0, 5)`;
})
.text((d: d3.HierarchyRectangularNode<IDatum>) => d.data.name);
};
d3.json("./data/games.json").then((data: any) => {
root = d3.partition<IDatum>().size([2 * Math.PI, height / 1.6])(
d3
.hierarchy<IDatum>(data)
.sum((d: IDatum) => d.popularity || 0)
.sort(
(a: d3.HierarchyNode<IDatum>, b: d3.HierarchyNode<IDatum>) =>
(b.data.popularity || 0) - (a.data.popularity || 0)
)
);
render(root);
});
});
return (
<>
<svg ref={svg}></svg>
</>
);
};
export { SunBurst };
原文地址:https://www.cnblogs.com/xiaoxu-xmy/p/13772942.html
GitHub: https://github.com/lemon-Xu/Learning-d3.-Js
作者: lemon