国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

D3.js實現雷達圖的方法詳解

2019-11-20 08:55:06
字體:
來源:轉載
供稿:網友

前言

再簡單介紹下D3.js,D3.js 是一個基于數據操作文檔JavaScript庫。D3幫助你給數據帶來活力通過使用HTML、SVG和CSS。D3重視Web標準為你提供現代瀏覽器的全部功能,而不是給你一個專有的框架。結合強大的可視化組件和數據驅動方式Dom操作。這里也可以看到它是用SVG來呈現圖表的,所以使用D3.js是需要一定的SVG基礎的。

本文依然是先把簡單的畫圖框架搭起來,添加SVG畫布。這里和餅圖有點類似,為了方便后面的繪制,我們把組合這些元素的g元素移動到畫布的中心:

<!DOCTYPE html><html lang="en"> <head>  <meta charset="UTF-8">  <title>雷達圖</title>  <style>   .container {    margin: 30px auto;    width: 600px;    height: 300px;    border: 1px solid #000;   }  </style> </head> <body>  <div class="container">   <svg width="100%" height="100%"></svg>  </div>  <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>  <script>   window.onload = function() {    var width = 600, height = 300;    // 創建一個分組用來組合要畫的圖表元素    var main = d3.select('.container svg').append('g')      .classed('main', true)      .attr('transform', "translate(" + width/2 + ',' + height/2 + ')');   };   function getColor(idx) {    var palette = [     '#2ec7c9', '#b6a2de', '#5ab1ef', '#ffb980', '#d87a80',     '#8d98b3', '#e5cf0d', '#97b552', '#95706d', '#dc69aa',     '#07a2a4', '#9a7fd1', '#588dd5', '#f5994e', '#c05050',     '#59678c', '#c9ab00', '#7eb00a', '#6f5553', '#c14089'    ]    return palette[idx % palette.length];   }  </script> </body></html>

這里為什么我會說雷達圖和餅圖會有點類似呢?看一下下面這張圖。

可以看到,雷達圖的網軸(藍色部分)是由多個正多邊形所組成的,而正多邊形的繪制正好是可以利用圓半徑的特性來繪制的,所以從一開始把繪制的原點移動到畫布的中心是很方便后面的繪制工作的。

模擬數據

我們先模擬一些原始數據。

var data = { fieldNames: ['語文','數學','外語','物理','化學','生物','政治','歷史'], values: [  [10,20,30,40,50,60,70,80] ]};

計算網軸坐標并繪制

在前面的其他圖表的實現中,都有比例尺或者布局這樣的東西來為我們轉化數據提供便利,雷達圖是否也存在這樣的工具函數呢?答案是沒有!沒有!沒有!重要的事情說三遍!(-_-) 所以,我們只能開動自己的小腦瓜自己算了。

// 設定一些方便計算的常量var radius = 100, // 指標的個數,即fieldNames的長度 total = 8, // 需要將網軸分成幾級,即網軸上從小到大有多少個正多邊形 level = 4, // 網軸的范圍,類似坐標軸 rangeMin = 0, rangeMax = 100, arc = 2 * Math.PI;// 每項指標所在的角度var onePiece = arc/total;// 計算網軸的正多邊形的坐標var polygons = { webs: [], webPoints: []};for(var k=level;k>0;k--) { var webs = '',   webPoints = []; var r = radius/level * k; for(var i=0;i<total;i++) {  var x = r * Math.sin(i * onePiece),   y = r * Math.cos(i * onePiece);  webs += x + ',' + y + ' ';  webPoints.push({   x: x,   y: y  }); } polygons.webs.push(webs); polygons.webPoints.push(webPoints);} 

計算網軸的坐標就是計算一個個多邊形的各點坐標,為了后面添加polygon元素時方便繪制(points屬性的賦值),我們需要在求點坐標的時候順便把它們拼成字符串。上述代碼的for循環中,外層循環代表一個多邊形,內層循環代表多邊形上的點,多邊形與多邊形之間差異僅僅在于它們的外圓的半徑不同,而同一多邊形的點與點之間的差異在于它們的角度不同。點的坐標由半徑乘以角度的正弦或者余弦來求得。

得到了計算好的坐標以后,我們就開始添加網軸。

// 繪制網軸var webs = main.append('g')  .classed('webs', true);webs.selectAll('polygon')  .data(polygons.webs)  .enter()  .append('polygon')  .attr('points', function(d) {   return d;  });

添加一個g元素用來組合所有代表網軸的元素,選擇其中的polygon元素并綁定polygons.webs數組,enter()搭配append()添加新的polygon元素,對points屬性進行復制。完成這一系列在前面幾篇文章中已經反復練習的操作以后,為了讓網軸更加的明顯,我們給它加一點樣式。

.webs polygon { fill: white; fill-opacity: 0.5; stroke: gray; stroke-dasharray: 10 5;} 

我們得到了如下圖所示的網軸。

添加縱軸

接著我們把縱軸也添加上。縱軸就是添加一根根的線條,連接中心點和最外層的多邊形上的點,需要的數據可以從polygons.webPoints[0]中取。

// 添加縱軸var lines = main.append('g')  .classed('lines', true);lines.selectAll('line')  .data(polygons.webPoints[0])  .enter()  .append('line')  .attr('x1', 0)  .attr('y1', 0)  .attr('x2', function(d) {   return d.x;  })  .attr('y2', function(d) {   return d.y;  });

雷達圖的坐標軸部分就完成了。

計算雷達圖區域并添加

雷達圖區域也是一個多邊形,只不過是一個不規則的多邊形。但是他的幾個點始終處在縱軸上,并且點在縱軸上的位置可以通過點所代表的值在縱軸范圍內的占比計算出來的。

// 計算雷達圖表的坐標var areasData = [];var values = data.values;for(var i=0;i<values.length;i++) { var value = values[i],   area = '',   points = []; for(var k=0;k<total;k++) {  var r = radius * (value[k] - rangeMin)/(rangeMax - rangeMin);  var x = r * Math.sin(k * onePiece),   y = r * Math.cos(k * onePiece);  area += x + ',' + y + ' ';  points.push({   x: x,   y: y  }) } areasData.push({  polygon: area,  points: points });}

計算完點的坐標以后我們就可以添加雷達圖區域了。為了使雷達圖更可觀,我們除了添加多邊形表示雷達圖的區域以外,也把多邊形在各縱軸上的點標記出來。

// 添加g分組包含所有雷達圖區域var areas = main.append('g') .classed('areas', true);// 添加g分組用來包含一個雷達圖區域下的多邊形以及圓點 areas.selectAll('g') .data(areasData) .enter() .append('g') .attr('class',function(d, i) {  return 'area' + (i+1); });for(var i=0;i<areasData.length;i++) { // 依次循環每個雷達圖區域 var area = areas.select('.area' + (i+1)),   areaData = areasData[i]; // 繪制雷達圖區域下的多邊形 area.append('polygon')   .attr('points', areaData.polygon)   .attr('stroke', function(d, index) {    return getColor(i);   })   .attr('fill', function(d, index) {    return getColor(i);   }); // 繪制雷達圖區域下的點  var circles = area.append('g')   .classed('circles', true); circles.selectAll('circle')   .data(areaData.points)   .enter()   .append('circle')   .attr('cx', function(d) {    return d.x;   })   .attr('cy', function(d) {    return d.y;   })   .attr('r', 3)   .attr('stroke', function(d, index) {    return getColor(i);   }); }

這里為了體驗層次關系,我用areas包含住所有雷達圖區域,又在里面用一個g分組表示一個雷達圖區域,在雷達圖區域里包含組成該區域的多邊形和圓點。這里因為我們數據用一個雷達圖區域就表示了,所以這個for循環只會循環一次。給繪制好的區域加上樣式。

.areas polygon { fill-opacity: 0.5; stroke-width: 3;}.areas circle { fill: white; stroke-width: 3;}

于是得到了下圖這個樣子的圖表。

計算文字標簽坐標并添加

為了讓上面的圖表更完整一些,我們給它加上文字標簽。文字標簽標注在網軸的外圍,所以可以以計算網軸多邊形點坐標的同樣的原理計算文字標簽的坐標。

// 計算文字標簽坐標var textPoints = [];var textRadius = radius + 20;for(var i=0;i<total;i++) { var x = textRadius * Math.sin(i * onePiece),   y = textRadius * Math.cos(i * onePiece); textPoints.push({  x: x,  y: y });} 

計算好坐標以后再添加到畫布中。

// 繪制文字標簽var texts = main.append('g')  .classed('texts', true);texts.selectAll('text')  .data(textPoints)  .enter()  .append('text')  .attr('x', function(d) {   return d.x;  })  .attr('y', function(d) {   return d.y;  })  .text(function(d,i) {   return data.fieldNames[i];  }); 

最后的樣子是這樣的。

總結

以上就是利用D3.js實現雷達的全部內容,希望這篇文章對大家的學習和工作能有所幫助。如果有疑問大家可以留言交流,感興趣的朋友們請大家繼續關注武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 马龙县| 壶关县| 古浪县| 渭源县| 呼图壁县| 西乡县| 珲春市| 广丰县| 桓仁| 邳州市| 石河子市| 南皮县| 集贤县| 承德县| 宁强县| 平阳县| 林口县| 固安县| 昌乐县| 石嘴山市| 祁东县| 馆陶县| 邵武市| 岐山县| 武川县| 报价| 怀仁县| 读书| 哈巴河县| 施甸县| 平和县| 宝鸡市| 商南县| 开平市| 沛县| 江山市| 通榆县| 元江| 尼木县| 类乌齐县| 桦南县|