d3分区扇形拼接雷达图(regional_radar),vue组件间通信,js模块和vue组件互相引用,vue-router,element-ui,axios,echarts,less(开箱即用)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dengzeyuan/article/details/80634277

项目基于vue-v2.x版本搭建,包含了:vue组件,组件间通信,外部js模块和vue组件的互相引用,vue-router,element-ui,axios,echarts,less(全部配置好,开箱即用)。 分区域雷达图通过d3完成,每个区域代表唯一的分类和对应的子类(每个子类坐标单位不同,也为唯一),通过多个扇形区域拼接成一个完整雷达图(regional_radar)

分区域扇形雷达图(regional_radar),需求为将不同类别对应展示数值的子类(每个子类坐标展示唯一)都拼接到一个雷达图里显示。(用echarts没有实现坐标轴,为了方便了后面扩展所以用了d3.js)

完整项目在GitHub上面,这里面只做简单的介绍。

GitHub地址:https://github.com/dengzeyuan/regional_radar

需求如下图所示:

仔细观察坐标轴!!!每一个分类展示的坐标轴都是唯一的。

启动项目基于vue2.x,d3画图实现方法为一个大分类为一个扇形,通过遍历json数据里的类型对象个数画出对应的分类扇形,通过拼接各个扇形组成一个完整雷达图,并且实现点击不同分类区域事件(点击之后查找相应分类下所有要展示的子类,通过柱形图和折线图或者饼图等等)

一、

Json格式为如下:

第一层对象为分类,第二层对象为坐标轴展示数据

先算出平均一份坐标轴的角度,因为每个扇形边线和坐标轴也要保持一个角度所以分类也要 +1,计算方式如下:

        let number = 0; //被除数
        data.type.forEach(function(d,v){
          number ++
          d.items.forEach(function(dc,vc){
            number ++;
          })

        })

let onePiece = 2 * Math.PI/number //每份平均所占角度

1.1

先根据开始和结束角度画出第一个分类最外层扇形,如下:

dataset = {

//原属角度范围

startAngle: 0,

endAngle: onePiece * d.items.length

};

// 外层弧度
let arcPath = d3
.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
main
.append("path")
.attr("d", arcPath(dataset))
.attr("fill", "none")
.attr("class", "radiusouter")
.attr("stroke", "black");

扇形的0°为箭头指向开始角度,转一圈为360(2 * Math.PI)

1.2

在画纵轴;

注意两点:

第一:因为线(line)是根据x,y轴坐标找点画线的,所以y轴向下为正,x轴向又为正,所以扇形开始从上向下,line开始从下向上,为了解
决这个问题,将计算出的line的y坐标取负值。

第二:第一条线(line)和扇形边线如果不做处理就会重合,所以要把扇形开始角度多减去一个角度平均值

完成之后如下图所示:

dataset = {

//原属角度范围

startAngle: 0-onePiece , //开始角度多减去一个平均角度值!!!

endAngle: onePiece * d.items.length

};

if (k == 3) {

//和外弧保持一致

r = radius;

}

for (let i = 0; i < d.items.length; i++) {

let x = r * Math.sin(i * onePiece),

y = r * Math.cos(i * onePiece);

webs += x + "," + y + " "; //坐标练成字符串

webPoints.push({ //坐标转化为对象

x: x,

y: -y //这里取负值即可和扇形保持同向绘制!!!

});

}

根据分类下的11个子元素,所以要用11条纵轴(扇形里的红线)来展示刻度值。

1.3

添加纵轴文字展示;

文字用svg的text添加,只需要x,y坐标和上面的纵轴的x1,y1保持一致即可。

ebPoints.push({ //坐标转化为对象,用于纵轴和文字坐标

x: x,

y: -y //这里取负值即可和扇形保持同向绘制!!!

});

坐标计算结果如下:

初步得到的文字展示如下:

最后在将文字旋转就可以避免重叠,暂时先不管样式。

1.4

分别添加最内层扇形和中间扇形,分别为 内层扇形半径 = 最外层半径*0.5(填充颜色为#ddd) 和 中间扇形半径 = 最外层半径*0.7(不做填充颜色)

注意:内层扇形要在纵轴添加完之后。才能保持层级覆盖在纵轴之上。

效果如下图所示:

1.5

最后在添加刻度和分类名称,效果图如下:

刻度坐标用的是上一步中计算扇形半径时一起得出的结果。只需要通过d3的data().enter().append(“text”,function(d){...})将文字添加即可。

样式也是暂时先不调,最后一起调样式。

到此为止,一个大分类下的扇形雷达已经完成。

二、

根据之前遍历数据的过程,本次该绘制第二个区域的扇形,

从第二个扇形开始的纵轴个数和扇形角度都要累加上一次的总和。这样才能保证后面的每个纵轴(line)计算出来的x,y坐标和扇形(arc)的startAngle,endAngle都是在上一次绘制扇形结束后紧接着累加向后增长的。这样才能将多个分区的扇形拼接成360°的一整个大闭合的圆形雷达图。

if (vindex !== 0) { //之后的每个扇形都累加上一次的总和

// debugger

starts = start =  ends + 1

ends = end = ends + type.items.length +1 ;

}else{ //第一个扇形

starts = start = 0;

ends = end = type.items.length;

}

纵轴和刻度坐标计算从第二个扇形开始都要累加上一次的结果

本次开始 = 上一次的结束总和 + 1(因为弧线和纵轴之间有一个平均角度的间隙所以要+1)

本次结束 = 本次数组长度 + 上一次结束总和 + 1

if(vindex == 0 ){

dataset = {

//原属角度范围

startAngle: 0-onePiece,

endAngle: onePiece * ends

};

}else{

dataset = {

//原属角度范围

startAngle: dataset.endAngle, 

endAngle: onePiece * ends

};

}

角度计算方式也和坐标一样

本次角度开始 = 上一次的结束角度总和 

本次角度结束 = 平均角度 * 之前所有数组长度总和

效果图如下:(字体重叠样式最后在调)

三、

根据遍历分类对象的长度依次循环画出对应个数的扇形,和对应纵轴,通过循环遍历的方法可以动态的创建分区域扇形个数和角度值大小。

四、

在计算value值在图形中的像素显示位置。

计算方式为:

let r = radius * 0.5 +(radius - radius * 0.5) *

(Number(type.items[indexflag].value) - 

Number(type.items[indexflag].rangeMin)) /

(Number(type.items[indexflag].rangeMax) -

Number(type.items[indexflag].rangeMin));

Value在雷达图像素位置 = value所占显示纵轴的比例长度 + 内层圆弧半径长度  

此结果不论坐标轴刻度为正和负值还是从大到小或者从小到大,雷达线所在图上的像素位置均正确。

最终完成效果图如下:

五、

可以点击不同分区进行其他操作。点击之后在相应的区域上加一层遮罩,如下所示:

猜你喜欢

转载自blog.csdn.net/dengzeyuan/article/details/80634277
今日推荐