|
@@ -0,0 +1,936 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="en">
|
|
|
+<head>
|
|
|
+ <meta charset="UTF-8">
|
|
|
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
|
+ <title>统计图表节点</title>
|
|
|
+ <style>
|
|
|
+ #mountNode {
|
|
|
+ background:#001528;
|
|
|
+ }
|
|
|
+ .graph-tooltip {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ border: 1px solid #e2e2e2;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #545454;
|
|
|
+ background-color: rgba(255, 255, 255, 0.9);
|
|
|
+ padding: 10px 8px;
|
|
|
+ box-shadow: rgb(174, 174, 174) 0px 0px 10px;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+</head>
|
|
|
+<body>
|
|
|
+ <div id="mountNode"></div>
|
|
|
+ <script src="../build/g6.js"></script>
|
|
|
+ <script>
|
|
|
+ /**
|
|
|
+ * 该案例演示如何使用G6自定义面积图节点
|
|
|
+ * by 镜曦
|
|
|
+ *
|
|
|
+ */
|
|
|
+ /**
|
|
|
+ * 注册一个类似南丁格尔玫瑰一样的节点
|
|
|
+ */
|
|
|
+ G6.registerNode('circleBar', {
|
|
|
+ draw(cfg, group) {
|
|
|
+ const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
|
|
+ const width = size[0];
|
|
|
+ const height = size[1];
|
|
|
+ /*
|
|
|
+ G:
|
|
|
+ Fan
|
|
|
+ x: 扇形圆心的 x 坐标
|
|
|
+ y: 扇形圆心的 y 坐标
|
|
|
+ rs: 内圈半径
|
|
|
+ re: 外圈半径
|
|
|
+ startAngle: 起点弧度
|
|
|
+ endAngle: 终点弧度
|
|
|
+ clockwise: 为true时顺时针渲染,为false时逆时针渲染
|
|
|
+ */
|
|
|
+ const baseR = 30;
|
|
|
+ let nowAngle = 0;
|
|
|
+ const everyIncAngle = 2 * Math.PI * (360 / 5 / 5) / 360;
|
|
|
+ cfg.details.forEach(cat =>{
|
|
|
+ cat.values.forEach(item =>{
|
|
|
+ const re = item+baseR;
|
|
|
+ const fan = group.addShape('fan', {
|
|
|
+ attrs:{
|
|
|
+ x:0,
|
|
|
+ y:0,
|
|
|
+ rs:baseR,
|
|
|
+ re:item+baseR,
|
|
|
+ startAngle:nowAngle,
|
|
|
+ endAngle: nowAngle += everyIncAngle,
|
|
|
+ clockwise:false,
|
|
|
+ stroke: 'darkgray',
|
|
|
+ fill:cat.color,
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 加上交互动画
|
|
|
+ fan.on('mouseenter', function(evt) {
|
|
|
+ fan.animate({
|
|
|
+ re: re + 8,
|
|
|
+ repeat: false
|
|
|
+ }, 300);
|
|
|
+ });
|
|
|
+ fan.on('mouseleave', function(evt) {
|
|
|
+ fan.animate({
|
|
|
+ re:re,
|
|
|
+ repeat: false
|
|
|
+ }, 300);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 设置class
|
|
|
+ fan.set("className", 'littleCircle');
|
|
|
+
|
|
|
+ });
|
|
|
+ });
|
|
|
+ group.addShape('circle', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ r: baseR,
|
|
|
+ fill: cfg.centerColor,
|
|
|
+ stroke:'darkgray',
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if(cfg.label) {
|
|
|
+ group.addShape('text', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ textAlign: 'center',
|
|
|
+ textBaseline: 'middle',
|
|
|
+ text: cfg.label,
|
|
|
+ fill: 'white',
|
|
|
+ fontStyle:'bold',
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return group;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 注册一个 分布在圆周上的折线图
|
|
|
+ */
|
|
|
+ G6.registerNode('circleLine', {
|
|
|
+ draw(cfg, group) {
|
|
|
+ const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
|
|
+ const width = size[0];
|
|
|
+ const height = size[1];
|
|
|
+
|
|
|
+ const baseR = 30;
|
|
|
+ let nowAngle = 0;
|
|
|
+
|
|
|
+ // Ref line
|
|
|
+ let refR = baseR;
|
|
|
+ const refInc = 10;
|
|
|
+ for(let i = 0; i< 5; i++){
|
|
|
+ group.addShape('circle', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ r: refR += refInc,
|
|
|
+ stroke:'rgba(255,255,255,0.4)',
|
|
|
+ lineDash:[4, 4],
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ const everyIncAngle = 2 * Math.PI * (360 / 5 / 5) / 360;
|
|
|
+ cfg.details.forEach(cat =>{
|
|
|
+ // 计算一系列点的位置
|
|
|
+ const postions = [];
|
|
|
+ cat.values.forEach((item, index) =>{
|
|
|
+ const r = baseR + item;
|
|
|
+ const xPos = r * Math.cos(nowAngle);
|
|
|
+ const yPos = r * Math.sin(nowAngle);
|
|
|
+ nowAngle += everyIncAngle;
|
|
|
+ postions.push([xPos, yPos]);
|
|
|
+ if(index === 4){
|
|
|
+ const r = baseR + item;
|
|
|
+ const xPos = r * Math.cos(nowAngle );
|
|
|
+ const yPos = r * Math.sin(nowAngle );
|
|
|
+ postions.push([xPos, yPos]);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ const pathArrayL = postions.map(item =>(["L", ...item]));
|
|
|
+ // 添加连线
|
|
|
+ const shape = group.addShape('path', {
|
|
|
+ attrs: {
|
|
|
+ path: [
|
|
|
+ ['M', 0, 0 ], // 上部顶点
|
|
|
+ ...pathArrayL,
|
|
|
+ ['Z'] // 封闭
|
|
|
+ ],
|
|
|
+ stroke: cat.color // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 添加标注点
|
|
|
+ postions.forEach(( pos, index )=>{
|
|
|
+ if(index !== 5){
|
|
|
+ const littleCircle = group.addShape('circle', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: pos[0], // 居中
|
|
|
+ y: pos[1],
|
|
|
+ r: 2,
|
|
|
+ fill: 'black',
|
|
|
+ stroke:cat.color,
|
|
|
+ cursor: "pointer",
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 加上交互动画
|
|
|
+ littleCircle.on('mouseenter', function(evt) {
|
|
|
+ littleCircle.animate({
|
|
|
+ r: 5,
|
|
|
+ repeat: false
|
|
|
+ }, 200);
|
|
|
+ });
|
|
|
+ littleCircle.on('mouseleave', function(evt) {
|
|
|
+ littleCircle.animate({
|
|
|
+ r: 2,
|
|
|
+ repeat: false
|
|
|
+ }, 200);
|
|
|
+ });
|
|
|
+ // 设置class
|
|
|
+ littleCircle.set("className", 'littleCircle');
|
|
|
+ }
|
|
|
+
|
|
|
+ })
|
|
|
+
|
|
|
+ /*
|
|
|
+ const shape = group.addShape('path', {
|
|
|
+ attrs: {
|
|
|
+ path: [
|
|
|
+ ['M', 0, 0 ], // 上部顶点
|
|
|
+ ['L', width / 2, 0], // 右侧点
|
|
|
+ ['L', 0, height / 2], // 下部
|
|
|
+ ['L', - width / 2, 0], // 左侧
|
|
|
+ ['Z'] // 封闭
|
|
|
+ ],
|
|
|
+ stroke: cfg.color // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ */
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ // 添加一个和背景色相同的圆形
|
|
|
+ group.addShape('circle', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ r: baseR,
|
|
|
+ fill: cfg.centerColor,
|
|
|
+ stroke:'darkgray',
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if(cfg.label) {
|
|
|
+ group.addShape('text', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ textAlign: 'center',
|
|
|
+ textBaseline: 'middle',
|
|
|
+ text: cfg.label,
|
|
|
+ fill: 'white',
|
|
|
+ fontStyle:'bold',
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return group;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 注册一个 只有标注点
|
|
|
+ */
|
|
|
+ G6.registerNode('justPoints', {
|
|
|
+ draw(cfg, group) {
|
|
|
+ const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
|
|
+ const width = size[0];
|
|
|
+ const height = size[1];
|
|
|
+
|
|
|
+ const baseR = 30;
|
|
|
+ let nowAngle = 0;
|
|
|
+
|
|
|
+ // Ref line
|
|
|
+ let refR = baseR;
|
|
|
+ const refInc = 10;
|
|
|
+ for(let i = 0; i< 5; i++){
|
|
|
+ group.addShape('circle', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ r: refR += refInc,
|
|
|
+ stroke:'rgba(255,255,255,0.4)',
|
|
|
+ lineDash:[4, 4],
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ const everyIncAngle = 2 * Math.PI * (360 / 5 / 5) / 360;
|
|
|
+ nowAngle = nowAngle + everyIncAngle / 2;
|
|
|
+ cfg.details.forEach(cat =>{
|
|
|
+ // 计算一系列点的位置
|
|
|
+ const postions = [];
|
|
|
+ cat.values.forEach((item, index) =>{
|
|
|
+ const r = baseR + item;
|
|
|
+ const xPos = r * Math.cos(nowAngle);
|
|
|
+ const yPos = r * Math.sin(nowAngle);
|
|
|
+ nowAngle += everyIncAngle;
|
|
|
+ postions.push([xPos, yPos]);
|
|
|
+ if(index === 4){
|
|
|
+ const r = baseR + item;
|
|
|
+ const xPos = r * Math.cos(nowAngle );
|
|
|
+ const yPos = r * Math.sin(nowAngle );
|
|
|
+ postions.push([xPos, yPos]);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ // 添加标注点
|
|
|
+ postions.forEach(( pos, index )=>{
|
|
|
+ if(index !== 5){
|
|
|
+ group.addShape('circle', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: pos[0], // 居中
|
|
|
+ y: pos[1],
|
|
|
+ r: 2,
|
|
|
+ fill: 'black',
|
|
|
+ stroke:cat.color,
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ })
|
|
|
+
|
|
|
+ /*
|
|
|
+ const shape = group.addShape('path', {
|
|
|
+ attrs: {
|
|
|
+ path: [
|
|
|
+ ['M', 0, 0 ], // 上部顶点
|
|
|
+ ['L', width / 2, 0], // 右侧点
|
|
|
+ ['L', 0, height / 2], // 下部
|
|
|
+ ['L', - width / 2, 0], // 左侧
|
|
|
+ ['Z'] // 封闭
|
|
|
+ ],
|
|
|
+ stroke: cfg.color // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ */
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ let nowAngle2 = 0;
|
|
|
+ const everyIncAngleCat = 2 * Math.PI * (360 / 5 ) / 360;
|
|
|
+ for(let i = 0; i < 5; i++){
|
|
|
+ const r = 30 + 50;
|
|
|
+ const xPos = r * Math.cos(nowAngle2);
|
|
|
+ const yPos = r * Math.sin(nowAngle2);
|
|
|
+
|
|
|
+ const shape = group.addShape('path', {
|
|
|
+ attrs: {
|
|
|
+ path: [
|
|
|
+ ['M', 0, 0 ],
|
|
|
+ ['L', xPos, yPos],
|
|
|
+
|
|
|
+ ],
|
|
|
+ lineDash:[4, 4],
|
|
|
+
|
|
|
+ stroke: 'darkgray' // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
|
|
+ }
|
|
|
+ });
|
|
|
+ nowAngle2 += everyIncAngleCat;
|
|
|
+ }
|
|
|
+ // 添加一个和背景色相同的圆形
|
|
|
+ group.addShape('circle', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ r: baseR,
|
|
|
+ fill: cfg.centerColor,
|
|
|
+ stroke:'darkgray',
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ if(cfg.label) {
|
|
|
+ group.addShape('text', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ textAlign: 'center',
|
|
|
+ textBaseline: 'middle',
|
|
|
+ text: cfg.label,
|
|
|
+ fill: 'white',
|
|
|
+ fontStyle:'bold',
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return group;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 注册一个 面积图节点
|
|
|
+ */
|
|
|
+ G6.registerNode('area', {
|
|
|
+ draw(cfg, group) {
|
|
|
+ const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
|
|
+ const width = size[0];
|
|
|
+ const height = size[1];
|
|
|
+
|
|
|
+ const baseR = 30;
|
|
|
+ let nowAngle = 0;
|
|
|
+
|
|
|
+ // Ref line
|
|
|
+ let refR = baseR;
|
|
|
+ const refInc = 10;
|
|
|
+ for(let i = 0; i< 6; i++){
|
|
|
+ group.addShape('circle', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ r: refR += refInc,
|
|
|
+ stroke:'rgba(255,255,255,0.4)',
|
|
|
+ lineDash:[4, 4],
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ const everyIncAngle = 2 * Math.PI * (360 / 5 ) / 360;
|
|
|
+ const tempIncValues = [baseR, baseR, baseR, baseR, baseR];
|
|
|
+ const allRs = [];
|
|
|
+ cfg.details.forEach(cat =>{
|
|
|
+
|
|
|
+ const oneRs = [];
|
|
|
+ cat.values.forEach((v, i) =>{
|
|
|
+ const R = tempIncValues[i] + v * 0.4;
|
|
|
+ oneRs.push(R);
|
|
|
+ tempIncValues[i] = R;
|
|
|
+ });
|
|
|
+ allRs.push(oneRs);
|
|
|
+
|
|
|
+ });
|
|
|
+ const strokeColors = [
|
|
|
+ 'rgba(37,203,253,1)',
|
|
|
+ 'rgba(254,255,123,1)',
|
|
|
+ 'rgba(254,171,58,1)',
|
|
|
+ 'rgba(254,87,102,1)',
|
|
|
+ 'rgba(22,193,118,1)',
|
|
|
+ ];
|
|
|
+ const fillColors = [
|
|
|
+ 'rgba(37,203,253,0.5)',
|
|
|
+ 'rgba(254,255,123,0.5)',
|
|
|
+ 'rgba(254,171,58,0.5)',
|
|
|
+ 'rgba(254,87,102,0.5)',
|
|
|
+ 'rgba(22,193,118,0.5)',
|
|
|
+ ];
|
|
|
+
|
|
|
+
|
|
|
+ allRs.reverse().forEach((Rs, index) =>{
|
|
|
+ let curAngle = 0;
|
|
|
+ const poss = [];
|
|
|
+ Rs.forEach(r=>{
|
|
|
+ const xPos = r * Math.cos(curAngle);
|
|
|
+ const yPos = r * Math.sin(curAngle);
|
|
|
+ curAngle += everyIncAngle;
|
|
|
+ poss.push([xPos, yPos]);
|
|
|
+ });
|
|
|
+ const Ls = poss.map((p, i)=>{
|
|
|
+ if( i === 0 ){
|
|
|
+ return ["M", ...p]
|
|
|
+ }
|
|
|
+ return ["L", ...p]
|
|
|
+ });
|
|
|
+ console.log('Ls', ...Ls);
|
|
|
+ const shape = group.addShape('path', {
|
|
|
+ attrs: {
|
|
|
+ path: [
|
|
|
+ ...Ls,
|
|
|
+ ['Z'] // 封闭
|
|
|
+ ],
|
|
|
+ stroke:strokeColors[index] ,
|
|
|
+ fill:fillColors[index],
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ });
|
|
|
+ let nowAngle2 = 0;
|
|
|
+ const everyIncAngleCat = 2 * Math.PI * (360 / 5 ) / 360;
|
|
|
+ for(let i = 0; i < 5; i++){
|
|
|
+ const r = 30 + 60;
|
|
|
+ const xPos = r * Math.cos(nowAngle2);
|
|
|
+ const yPos = r * Math.sin(nowAngle2);
|
|
|
+
|
|
|
+ const shape = group.addShape('path', {
|
|
|
+ attrs: {
|
|
|
+ path: [
|
|
|
+ ['M', 0, 0 ],
|
|
|
+ ['L', xPos, yPos],
|
|
|
+
|
|
|
+ ],
|
|
|
+ lineDash:[4, 4],
|
|
|
+
|
|
|
+ stroke: 'darkgray' // 颜色应用到边上,如果应用到填充,则使用 fill: cfg.color
|
|
|
+ }
|
|
|
+ });
|
|
|
+ nowAngle2 += everyIncAngleCat;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加一个和背景色相同的圆形
|
|
|
+ group.addShape('circle', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ r: baseR,
|
|
|
+ fill: cfg.centerColor,
|
|
|
+ stroke:'darkgray',
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ if(cfg.label) {
|
|
|
+ group.addShape('text', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ textAlign: 'center',
|
|
|
+ textBaseline: 'middle',
|
|
|
+ text: cfg.label,
|
|
|
+ fill: 'white',
|
|
|
+ fontStyle:'bold'
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return group;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ 环 1
|
|
|
+ */
|
|
|
+ G6.registerNode('rings1', {
|
|
|
+ draw(cfg, group) {
|
|
|
+ const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
|
|
+ const width = size[0];
|
|
|
+ const height = size[1];
|
|
|
+ /*
|
|
|
+ G:
|
|
|
+ Fan
|
|
|
+ x: 扇形圆心的 x 坐标
|
|
|
+ y: 扇形圆心的 y 坐标
|
|
|
+ rs: 内圈半径
|
|
|
+ re: 外圈半径
|
|
|
+ startAngle: 起点弧度
|
|
|
+ endAngle: 终点弧度
|
|
|
+ clockwise: 为true时顺时针渲染,为false时逆时针渲染
|
|
|
+ */
|
|
|
+ const baseR = 30;
|
|
|
+ let nowAngle = 0;
|
|
|
+ const everyIncAngle = 2 * Math.PI * (360 / 5 / 5) / 360;
|
|
|
+ cfg.details.forEach(cat =>{
|
|
|
+ cat.values.forEach(item =>{
|
|
|
+ const baseNbr = Math.ceil(item / 10);
|
|
|
+ const baseIncR = 7;
|
|
|
+ let nowStartR = baseR;
|
|
|
+ const last = item % 10;
|
|
|
+ const endAngle = nowAngle + everyIncAngle;
|
|
|
+ for (let i = 0; i < baseNbr ; i ++ ) {
|
|
|
+ const fan = group.addShape('fan', {
|
|
|
+ attrs:{
|
|
|
+ x:0,
|
|
|
+ y:0,
|
|
|
+ rs:nowStartR,
|
|
|
+ re:nowStartR + baseIncR,
|
|
|
+ startAngle:nowAngle,
|
|
|
+ endAngle:endAngle,
|
|
|
+ clockwise:false,
|
|
|
+ stroke: 'darkgray',
|
|
|
+ fill:cat.color,
|
|
|
+ }
|
|
|
+ });
|
|
|
+ nowStartR = nowStartR + baseIncR + 2
|
|
|
+ if(i === baseNbr -1 && last !== 0){
|
|
|
+ const fan = group.addShape('fan', {
|
|
|
+ attrs:{
|
|
|
+ x:0,
|
|
|
+ y:0,
|
|
|
+ rs:nowStartR,
|
|
|
+ re:nowStartR + baseIncR * last / 10,
|
|
|
+ startAngle:nowAngle,
|
|
|
+ endAngle:endAngle,
|
|
|
+ clockwise:false,
|
|
|
+ stroke: 'darkgray',
|
|
|
+ fill:cat.color,
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ nowAngle = endAngle
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ group.addShape('circle', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ r: baseR,
|
|
|
+ fill: cfg.centerColor,
|
|
|
+ stroke:'darkgray',
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if(cfg.label) {
|
|
|
+ group.addShape('text', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ textAlign: 'center',
|
|
|
+ textBaseline: 'middle',
|
|
|
+ text: cfg.label,
|
|
|
+ fill: 'white',
|
|
|
+ fontStyle:'bold',
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return group;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 注册一个 面积图节点
|
|
|
+ */
|
|
|
+ G6.registerNode('rings2', {
|
|
|
+ draw(cfg, group) {
|
|
|
+ const size = cfg.size || [40, 40]; // 如果没有 size 时的默认大小
|
|
|
+ const width = size[0];
|
|
|
+ const height = size[1];
|
|
|
+
|
|
|
+ const baseR = 30;
|
|
|
+ let nowAngle = 0;
|
|
|
+
|
|
|
+ // Ref line
|
|
|
+ let refR = baseR;
|
|
|
+ const refInc = 10;
|
|
|
+ for(let i = 0; i< 6; i++){
|
|
|
+ group.addShape('circle', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ r: refR += refInc,
|
|
|
+ stroke:'rgba(255,255,255,0.4)',
|
|
|
+ lineDash:[4, 4],
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ const everyIncAngle = 2 * Math.PI * (360 / 5 ) / 360;
|
|
|
+ const tempIncValues = [baseR, baseR, baseR, baseR, baseR];
|
|
|
+ const allRs = [];
|
|
|
+ cfg.details.forEach(cat =>{
|
|
|
+
|
|
|
+ const oneRs = [];
|
|
|
+ cat.values.forEach((v, i) =>{
|
|
|
+ const R = tempIncValues[i] + v * 0.4;
|
|
|
+ oneRs.push(R);
|
|
|
+ tempIncValues[i] = R;
|
|
|
+ });
|
|
|
+ allRs.push(oneRs);
|
|
|
+
|
|
|
+ });
|
|
|
+ const strokeColors = [
|
|
|
+ 'rgba(37,203,253,1)',
|
|
|
+ 'rgba(254,255,123,1)',
|
|
|
+ 'rgba(254,171,58,1)',
|
|
|
+ 'rgba(254,87,102,1)',
|
|
|
+ 'rgba(22,193,118,1)',
|
|
|
+ ];
|
|
|
+ const fillColors = [
|
|
|
+ 'rgba(37,203,253,0.5)',
|
|
|
+ 'rgba(254,255,123,0.5)',
|
|
|
+ 'rgba(254,171,58,0.5)',
|
|
|
+ 'rgba(254,87,102,0.5)',
|
|
|
+ 'rgba(22,193,118,0.5)',
|
|
|
+ ];
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ allRs.reverse().forEach((Rs, index) =>{
|
|
|
+ let curAngle = 0;
|
|
|
+ const poss = [];
|
|
|
+ Rs.forEach(r=>{
|
|
|
+
|
|
|
+ const baseNbr = Math.ceil(r / 10);
|
|
|
+ const baseIncR = 7;
|
|
|
+ let nowStartR = baseR;
|
|
|
+ const last = r % 10;
|
|
|
+
|
|
|
+ for(let i = 0; i < baseNbr; i++){
|
|
|
+
|
|
|
+ const endAngle = nowAngle + everyIncAngle;
|
|
|
+
|
|
|
+ const fan = group.addShape('fan', {
|
|
|
+ attrs:{
|
|
|
+ x:0,
|
|
|
+ y:0,
|
|
|
+ rs:nowStartR,
|
|
|
+ re:nowStartR + baseIncR,
|
|
|
+ startAngle:nowAngle,
|
|
|
+ endAngle:endAngle,
|
|
|
+ clockwise:false,
|
|
|
+ stroke: 'darkgray',
|
|
|
+ fill:strokeColors[index],
|
|
|
+ }
|
|
|
+ });
|
|
|
+ nowStartR = nowStartR + baseIncR + 2
|
|
|
+ if(i === baseNbr -1 && last !== 0){
|
|
|
+ const fan = group.addShape('fan', {
|
|
|
+ attrs:{
|
|
|
+ x:0,
|
|
|
+ y:0,
|
|
|
+ rs:nowStartR,
|
|
|
+ re:nowStartR + baseIncR * last / 10,
|
|
|
+ startAngle:nowAngle,
|
|
|
+ endAngle:endAngle,
|
|
|
+ clockwise:false,
|
|
|
+ stroke: 'darkgray',
|
|
|
+ fill:strokeColors[index],
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ nowAngle = endAngle
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ // 添加一个和背景色相同的圆形
|
|
|
+ group.addShape('circle', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ r: baseR,
|
|
|
+ fill: cfg.centerColor,
|
|
|
+ stroke:'darkgray',
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ if(cfg.label) {
|
|
|
+ group.addShape('text', {
|
|
|
+ // attrs: style
|
|
|
+ attrs: {
|
|
|
+ x: 0, // 居中
|
|
|
+ y: 0,
|
|
|
+ textAlign: 'center',
|
|
|
+ textBaseline: 'middle',
|
|
|
+ text: cfg.label,
|
|
|
+ fill: 'white',
|
|
|
+ fontStyle:'bold'
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return group;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ /** 数据 */
|
|
|
+ const data = {
|
|
|
+ nodes: [{
|
|
|
+ id: 'nodeA',
|
|
|
+ x: 150,
|
|
|
+ y: 150,
|
|
|
+ label: 'Bar',
|
|
|
+ shape:'circleBar',
|
|
|
+ anchorPoints: [
|
|
|
+ [0, 0.5], [1, 0.5]
|
|
|
+ ],
|
|
|
+ details:[
|
|
|
+ {cat:'pv', values:[20,30,40,30,30], color:"#25cbfd"},
|
|
|
+ {cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
|
|
+ {cat:'uv', values:[40,30,30,40,40], color:"#feab3a"},
|
|
|
+ {cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
|
|
+ {cat:'cal', values:[10,10,20,20,20], color:"#16c176"},
|
|
|
+ ],
|
|
|
+ centerColor:'#0066FF',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 'nodeB',
|
|
|
+ x: 400,
|
|
|
+ y: 150,
|
|
|
+ label: 'Line',
|
|
|
+ shape:'circleLine',
|
|
|
+ anchorPoints: [
|
|
|
+ [0, 0.5], [1, 0.5]
|
|
|
+ ],
|
|
|
+ details:[
|
|
|
+ {cat:'pv', values:[20,30,40,30,30], color:"#25cbfd"},
|
|
|
+ {cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
|
|
+ {cat:'uv', values:[40,30,30,40,40], color:"#feab3a"},
|
|
|
+ {cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
|
|
+ {cat:'cal', values:[10,10,20,20,20], color:"#16c176"},
|
|
|
+ ],
|
|
|
+ centerColor:'#0066FF',
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ id: 'nodeC',
|
|
|
+ x: 650,
|
|
|
+ y: 150,
|
|
|
+ label: 'Point',
|
|
|
+ shape:'justPoints',
|
|
|
+ anchorPoints: [
|
|
|
+ [0, 0.5], [1, 0.5]
|
|
|
+ ],
|
|
|
+ details:[
|
|
|
+ {cat:'pv', values:[20,30,40,30,30], color:"#25cbfd"},
|
|
|
+ {cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
|
|
+ {cat:'uv', values:[40,30,30,40,40], color:"#feab3a"},
|
|
|
+ {cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
|
|
+ {cat:'cal', values:[10,10,20,20,20], color:"#16c176"},
|
|
|
+ ],
|
|
|
+ centerColor:'#0066FF',
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ id: 'nodeD',
|
|
|
+ x: 150,
|
|
|
+ y: 400,
|
|
|
+ label: 'Area',
|
|
|
+ shape:'area',
|
|
|
+ anchorPoints: [
|
|
|
+ [0, 0.5], [1, 0.5]
|
|
|
+ ],
|
|
|
+ details:[
|
|
|
+ {cat:'pv', values:[20,30,40,30,30], color:"#25cbfd"},
|
|
|
+ {cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
|
|
+ {cat:'uv', values:[40,30,30,40,40], color:"#feab3a"},
|
|
|
+ {cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
|
|
+ {cat:'cal', values:[10,10,20,20,20], color:"#16c176"},
|
|
|
+ ],
|
|
|
+ centerColor:'#0066FF',
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ id: 'nodeF',
|
|
|
+ x: 400,
|
|
|
+ y: 400,
|
|
|
+ label: 'Rings1',
|
|
|
+ shape:'rings1',
|
|
|
+ anchorPoints: [
|
|
|
+ [0, 0.5], [1, 0.5]
|
|
|
+ ],
|
|
|
+ details:[
|
|
|
+ {cat:'pv', values:[20,30,48,30,30], color:"#25cbfd"},
|
|
|
+ {cat:'dal', values:[40,30,20,30,50], color:"#feff7b"},
|
|
|
+ {cat:'uv', values:[40,30,30,4,40], color:"#feab3a"},
|
|
|
+ {cat:'sal', values:[20,30,50,20,20], color:"#fe5766"},
|
|
|
+ {cat:'cal', values:[10,10,25,20,20], color:"#16c176"},
|
|
|
+ ],
|
|
|
+ centerColor:'#0066FF',
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ ],
|
|
|
+ edges: [
|
|
|
+ //{source:'nodeA', target:'nodeB', color:"rgba(0, 255, 255, 0.5)"},
|
|
|
+ //{source:'nodeB', target:'nodeC', color:"rgba(0, 255, 255, 0.5)"},
|
|
|
+
|
|
|
+ ]
|
|
|
+ };
|
|
|
+
|
|
|
+ const graph = new G6.Graph({
|
|
|
+ container: 'mountNode',
|
|
|
+ width: 1000,
|
|
|
+ height: 600
|
|
|
+ });
|
|
|
+
|
|
|
+ graph.on("node:mouseenter", function(event) {
|
|
|
+ var node = event.item;
|
|
|
+ var nodeId = node.get("model").id;
|
|
|
+ var shape = event.target;
|
|
|
+
|
|
|
+ if (shape.get("className") === "littleCircle") {
|
|
|
+ // 如果点击是发生在节点里面的小圆上,显示tooltip
|
|
|
+ console.log('x', event);
|
|
|
+ console.log('Y', event);
|
|
|
+
|
|
|
+ showTooltip("tooltip for " + nodeId, {
|
|
|
+ x: event.x,
|
|
|
+ y: event.y
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 否则隐藏tooltip
|
|
|
+ hideTooltip();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ graph.on("node:mouseleave", function(event) {
|
|
|
+ hideTooltip();
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ graph.data(data);
|
|
|
+ graph.render();
|
|
|
+
|
|
|
+ var tooltipEl = null;
|
|
|
+ // 在指定的位置显示tooltip
|
|
|
+ function showTooltip(message, position) {
|
|
|
+ const offSetX = 50;
|
|
|
+ if (!tooltipEl) {
|
|
|
+ var container = document.getElementById("mountNode");
|
|
|
+ tooltipEl = document.createElement("div");
|
|
|
+ tooltipEl.setAttribute("class", "graph-tooltip");
|
|
|
+ container.appendChild(tooltipEl);
|
|
|
+ }
|
|
|
+ tooltipEl.textContent = message;
|
|
|
+ // tooltip是相对于画布canvas element绝对定位,所以position的x,y必须是相对于画布的坐标
|
|
|
+ tooltipEl.style.left = position.x + offSetX+ "px";
|
|
|
+ tooltipEl.style.top = position.y + "px";
|
|
|
+ tooltipEl.style.display = "block";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 隐藏tooltip
|
|
|
+ function hideTooltip() {
|
|
|
+ if (!tooltipEl) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ tooltipEl.style.display = "none";
|
|
|
+ }
|
|
|
+ </script>
|
|
|
+</body>
|
|
|
+</html>
|