D3.js(v3)+react 製作 一個帶坐標軸與比例尺的折線圖

来源:https://www.cnblogs.com/littleSpill/archive/2019/05/19/10891161.html
-Advertisement-
Play Games

本章使用路徑生成器來繪製一個折線圖。以中國和日本的GDP數據為例: 1 //數據 2 var dataList = [ 3 { 4 coountry : "china", 5 gdp : [ 6 [2000,11920],[2001,13170],[2002,14550],[2003,16500], ...


本章使用路徑生成器來繪製一個折線圖。以中國和日本的GDP數據為例:  
 1    //數據
 2         var dataList = [
 3             {
 4                 coountry : "china",
 5                 gdp : [
 6                     [2000,11920],[2001,13170],[2002,14550],[2003,16500],[2004,19440],[2005,22870],
 7                     [2006,27930],[2007,35040],[2008,45470],[2009,51050],[2010,59490],[2011,73140],
 8                     [2012,83860],[2013,103550]
 9                 ]
10             },
11             {
12                 coountry : "japan",
13                 gdp : [
14                     [2000,47310],[2001,41590],[2002,39800],[2003,43020],[2004,46500],[2005,45710],
15                     [2006,43560],[2007,43560],[2008,48490],[2009,50350],[2010,54950],[2011,59050],
16                     [2012,59370],[2013,48980]
17                 ]
18             }
19         ]

 

dataList是一個數組,每一項是一個對象,對象里有兩個成員,國家名稱country和國民生產總值GDP。GDP也是一個數組,其中[2000,11920]表示2000年的GDP為11920億美元。 首先,定義x軸和y軸的比例尺,x軸表示年份,y軸表示GDP值。定義比例尺之前,要明確繪製區域和GDP的最大值:  
 1      //外邊框
 2         var padding = {top : 50 , right : 50 , bottom : 100 , left : 200};
 3 
 4         //計算GDP的最大值
 5         var gdpmax = 0;
 6         for (var i = 0; i < dataList.length ; i++){
 7             var currGdp = d3.max(dataList[i].gdp,function(d){
 8                 return d[1]
 9             })
10             if(currGdp > gdpmax){
11                 gdpmax = currGdp
12             }
13         }

 

padding是到SVG畫板上下左右各邊界的距離,單位為像素。GDP的最大值保存在gdpmax變數中。使用d3.max()可以很方便的求數組中的最大值。接下來,憑藉padding和gdpmax定義比例尺的定義域和值域:  
1       //定義比例尺,均為線性比例尺
2         var xScale = d3.scale.linear()                                  //定義一個比例尺
3                         .domain([min,max])                              //設定x軸的值域
4                         .range([0,width-padding.left - padding.right])  //設定x軸的定義域
5 
6         var yScale = d3.scale.linear()                                  //定義一個比例尺
7                         .domain([0,gdpmax*1.1])                         //設定y軸的值域
8                         .range([height-padding.top-padding.bottom,0])   //設定y軸的定義域

 

x軸的定義域是2000~2013,此外為了代碼簡潔手動指定了,實際應用時應從數據中獲取。y軸的定義域是0~gdpmax*1.1,乘以1.1是為了使得圖形不在坐標軸的邊界繪製。接下來根據數據定義一個線段生成器:  
1     //創建一個線段生成器
2         var linePath = d3.svg.line()                                    //創建一個線段生成器
3                        
4                         .x(function(d){return xScale(d[0])})            //設置x坐標的訪問器
5                         .y(function(d){return yScale(d[1])})            //設置y坐標的訪問器

 

該直線生成器的訪問器x為xScale(d[0]),y為yScale(d[1])。接下來要傳入的數據是gdp數組,如d為[2000,11920]這樣的值:那麼d[0]就是年份,d[1]是國民生產總值。對這兩個值都使用比例尺變換,則輸入的數據會自動按照比例伸縮後再生成直線路徑。   定義兩個RGB顏色,分別用於兩條折現的著色。然後,添加與數組dataList長度相同數量的<path>元素,並設置為線段生成器計算的路徑。代碼:  
 1       //定義兩個顏色
 2         var colors = [d3.rgb(0,0,255),d3.rgb(0,255,0)]
 3 
 4         //添加路徑
 5         svg.selectAll("path")                   //選擇svg中所有的path
 6             .data(dataList)                     //綁定數據
 7             .enter()                            //獲取enter部分
 8             .append("path")                     //添加足夠數量的<path>元素
 9             .attr("transform","translate("+padding.left + "," + padding.top + ")")  //平移
10             .attr("d",function(d){
11                 return linePath(d.gdp)          //返回線段生成器得到的路徑
12             })
13             .attr("fill","none")                //填充色為none
14             .attr("stroke",function(d,i){
15                 return colors[i]                //設置折線顏色
16             })
17             .attr("stroke-width","3px")         //設置折線的寬度

 

添加元素的形式"selectAll().data().enter().append()",相信大家都已經很熟悉了。給屬性transform賦予適當的值,令折線平移到指定的位置。在<path>元素的d屬性中,使用線段生成器計算路徑,註意linePath()的參數是d.gdp。此處的線段生成器是按照數組gdp的格式來設定訪問器的,因此一定要以d.gdp,而不是以d作為參數。   接下來繪製坐標軸:  
 1      //坐標軸x軸
 2         var xAxis = d3.svg.axis()               //創建一個新坐標軸
 3                     .scale(xScale)              //設定x坐標軸的比例尺
 4                     .ticks(6)                   //設定x坐標軸的分隔數
 5                     .tickFormat(d3.format("d")) //刻度的數組用字元串表示
 6                     .orient("bottom")           //設定x坐標軸的方向
 7         //坐標軸y軸
 8         var yAxis = d3.svg.axis()               //創建一個新坐標
 9                     .scale(yScale)              //設定y坐標軸的比例尺
10                     .orient("left")             //設定y坐標軸的方向
11 
12         //添加一個<g>元素用於放x軸
13         svg.append("g")                         //添加一個<g>元素
14             .attr("class","axis")               //定義class名
15             .attr("transform","translate("+padding.left + "," + (height-padding.bottom) + ")")  //平移
16             .call(xAxis)                        //call()應用
17 
18         //添加一個<g>元素用於放y軸
19         svg.append("g")                         //添加一個<g>元素
20             .attr("class","axis")               //定義class名
21             .attr("transform","translate("+ padding.left + "," + padding.top + ")")             //平移
22             .call(yAxis)                        //call()應用

 

由於x軸的刻度是年份的意思,而數據里的數據類型確實整數類型:所以如果直接在坐標軸上顯示,2000年會顯示成2,000, 2002年會顯示成2,002多一個逗號。因此,加了一條tickFormat(),其中,d3.format("d")表示刻度的數組都用字元串表示。設定之後,年份之間的逗號就會消失。然後,將兩個坐標軸分別放到兩個<g>元素里。   現在的效果圖如下:     如果想要使一段一段的直線看起來更光滑一些,可以使用直線生成器的插值函數。之前給大家介紹過,不清楚的點: https://www.cnblogs.com/littleSpill/p/10850364.html  設置為basis模式後,線段變為曲線。  
1      //創建一個線段生成器
2         var linePath = d3.svg.line()                                    //創建一個線段生成器
3                         .interpolate("basis")                           //使用basis插值模式
4                         .x(function(d){return xScale(d[0])})            //設置x坐標的訪問器
5                         .y(function(d){return yScale(d[1])})            //設置y坐標的訪問器

 

效果圖:     上面的折線圖還缺少一個標記,用戶不知道哪條直線是中國的GDP,哪條是日本的GDP。可添加兩個矩形,分別填充為相應的顏色。矩形邊上添加表示國家名稱的文字。  
 1       //添加兩個矩形標記
 2         var g = svg.selectAll("rect")           //將選擇集賦值給變數g
 3             .data(dataList)                     //綁定數據
 4             .enter()                            //獲取enter()部分
 5             .append("g")                        //添加<g>元素
 6         g.append("rect")                        //在<g>元素里添加<rect>矩形
 7             .attr("fill",function(d,i){         //設定顏色
 8                 return colors[i]
 9             })
10             .attr("transform",function(d,i){    //平移
11                 var x = padding.left + i*150
12                 var y = height - padding.bottom + 50
13                 return "translate(" +x + "," + y + ")"
14             })
15             .attr("width",20)                   //設定矩形的寬度
16             .attr("height",20)                  //設定矩形的高度
17 
18         //添加註解
19         g.append("text")                        //添加文字
20             .attr("class","text")               //定義class名
21             .attr("x",function(d,i){            //設定文字在x方向的位置
22                 return padding.left + i * 150 + 30
23             })
24             .attr("y",function(d,i){            //設定文字在y方向的位置
25                 return height - padding.bottom + 50 + 15
26             })
27             .text(function(d){                  //設定文字的內容
28                 return d.coountry
29             })
30             .attr("font-size","15px")           //設定文字的大小
31             .attr("fill","black")               //設定文字的顏色

 

如下圖: 一個完整的折線圖就做好了。            完整代碼:   
  1 import React, { Component } from 'react';
  2 import * as d3 from 'd3'
  3 class Line extends Component {
  4     constructor(props) {
  5         super(props);
  6         this.state = {}
  7     }
  8 
  9     componentDidMount(){
 10         this.oneMethod()
 11     }
 12 
 13     oneMethod(){
 14 
 15         var width = 800;                        //SVG繪製區域的寬度
 16         var height = 600;                       //SVG繪製區域的高度
 17 
 18         var svg = d3.select("#body")            //選擇id為body的div
 19                     .append("svg")              //在div中添加<svg>
 20                     .attr("width",width)        //設定<svg>的寬度
 21                     .attr("height",height)      //設定<svg>的高度
 22 
 23         //數據
 24         var dataList = [
 25             {
 26                 coountry : "china",
 27                 gdp : [
 28                     [2000,11920],[2001,13170],[2002,14550],[2003,16500],[2004,19440],[2005,22870],
 29                     [2006,27930],[2007,35040],[2008,45470],[2009,51050],[2010,59490],[2011,73140],
 30                     [2012,83860],[2013,103550]
 31                 ]
 32             },
 33             {
 34                 coountry : "japan",
 35                 gdp : [
 36                     [2000,47310],[2001,41590],[2002,39800],[2003,43020],[2004,46500],[2005,45710],
 37                     [2006,43560],[2007,43560],[2008,48490],[2009,50350],[2010,54950],[2011,59050],
 38                     [2012,59370],[2013,48980]
 39                 ]
 40             }
 41         ]
 42 
 43         //外邊框
 44         var padding = {top : 50 , right : 50 , bottom : 100 , left : 200};
 45 
 46         //計算GDP的最大值
 47         var gdpmax = 0;
 48         for (var i = 0; i < dataList.length ; i++){
 49             var currGdp = d3.max(dataList[i].gdp,function(d){
 50                 return d[1]
 51             })
 52             if(currGdp > gdpmax){
 53                 gdpmax = currGdp
 54             }
 55         }
 56 
 57         
 58         //先選出年份的最小值與最大值
 59         for (var i = 0; i < dataList.length ; i++){
 60             var min = d3.min(dataList[i].gdp,function(d){return d[0]})
 61             var max = d3.max(dataList[i].gdp,function(d){return d[0]})
 62         }
 63        //定義比例尺,均為線性比例尺
 64         var xScale = d3.scale.linear()                                  //定義一個比例尺
 65                         .domain([min,max])                              //設定x軸的值域
 66                         .range([0,width-padding.left - padding.right])  //設定x軸的定義域
 67 
 68         var yScale = d3.scale.linear()                                  //定義一個比例尺
 69                         .domain([0,gdpmax*1.1])                         //設定y軸的值域
 70                         .range([height-padding.top-padding.bottom,0])   //設定y軸的定義域
 71         //創建一個線段生成器
 72         var linePath = d3.svg.line()                                    //創建一個線段生成器
 73                         .interpolate("basis")                           //使用basis插值模式
 74                         .x(function(d){return xScale(d[0])})            //設置x坐標的訪問器
 75                         .y(function(d){return yScale(d[1])})            //設置y坐標的訪問器
 76 
 77         //定義兩個顏色
 78         var colors = [d3.rgb(0,0,255),d3.rgb(0,255,0)]
 79 
 80         //添加路徑
 81         svg.selectAll("path")                   //選擇svg中所有的path
 82             .data(dataList)                     //綁定數據
 83             .enter()                            //獲取enter部分
 84             .append("path")                     //添加足夠數量的<path>元素
 85             .attr("transform","translate("+padding.left + "," + padding.top + ")")  //平移
 86             .attr("d",function(d){
 87                 return linePath(d.gdp)          //返回線段生成器得到的路徑
 88             })
 89             .attr("fill","none")                //填充色為none
 90             .attr("stroke",function(d,i){
 91                 return colors[i]                //設置折線顏色
 92             })
 93             .attr("stroke-width","3px")         //設置折線的寬度
 94 
 95         //坐標軸x軸
 96         var xAxis = d3.svg.axis()               //創建一個新坐標軸
 97                     .scale(xScale)              //設定x坐標軸的比例尺
 98                     .ticks(6)                   //設定x坐標軸的分隔數
 99                     .tickFormat(d3.format("d")) //刻度的數組用字元串表示
100                     .orient("bottom")           //設定x坐標軸的方向
101         //坐標軸y軸
102         var yAxis = d3.svg.axis()               //創建一個新坐標
103                     .scale(yScale)              //設定y坐標軸的比例尺
104                     .orient("left")             //設定y坐標軸的方向
105 
106         //添加一個<g>元素用於放x軸
107         svg.append("g")                         //添加一個<g>元素
108             .attr("class","axis")               //定義class名
109             .attr("transform","translate("+padding.left + "," + (height-padding.bottom) + ")")  //平移
110             .call(xAxis)                        //call()應用
111 
112         //添加一個<g>元素用於放y軸
113         svg.append("g")                         //添加一個<g>元素
114             .attr("class","axis")               //定義class名
115             .attr("transform","translate("+ padding.left + "," + padding.top + ")")             //平移
116             .call(yAxis)                        //call()應用
117 
118         //添加兩個矩形標記
119         var g = svg.selectAll("rect")           //將選擇集賦值給變數g
120             .data(dataList)                     //綁定數據
121             .enter()                            //獲取enter()部分
122             .append("g")                        //添加<g>元素
123         g.append("rect")                        //在<g>元素里添加<rect>矩形
124             .attr("fill",function(d,i){         //設定顏色
125                 return colors[i]
126             })
127             .attr("transform",function(d,i){    //平移
128                 var x = padding.left + i*150
129                 var y = height - padding.bottom + 50
130                 return "translate(" +x + "," + y + ")"
131             })
132             .attr("width",20)                   //設定矩形的寬度
133             .attr("height",20)                  //設定矩形的高度
134 
135         //添加註解
136         g.append("text")                        //添加文字
137             .attr("class","text")               //定義class名
138             .attr("x",function(d,i){            //設定文字在x方向的位置
139                 return padding.left + i * 150 + 30
140             })
141             .attr("y",function(d,i){            //設定文字在y方向的位置
142                 return height - padding.bottom + 50 + 15
143             })
144             .text(function(d){                  //設定文字的內容
145                 return d.coountry
146             })
147             .attr("font-size","15px")           //設定文字的大小
148             .attr("fill","black")               //設定文字的顏色
149             
150     }
151     
152     render() {
153         return (
154             <div id="body" >
155                 
156             </div>
157         );
158     }
159 }
160 
161 export default Line;

 

     
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近做了一個Excel的多級聯動的功能,具體是將全國所有的氣象局按一二三四級單位做成四列,實現各級的聯動下拉選擇,這和省市縣鄉的各級聯動的功能基本一樣,下麵記錄下具體的操作步驟。 1、首先需要從資料庫中將所有單位按照Id ,父級ID ,單位名稱,導出excel, 2、將所有單位中的一級單位單獨取出作 ...
  • 寫一個符合自己要求使用透視存儲過程。在開發時,直接使用即可。 SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- -- Author: Insus.NET -- Create date: 2019-05-19 -- Update date: 201 ...
  • CPU 處理邏輯計算和記憶體管理,顯示操作。 GPU CPU無法顯示覆雜的圖形,GPU用於顯示覆雜圖形,分擔CPU的任務 xml佈局到屏幕的顯示流程:xml 通過 LayoutInflater 載入到記憶體中,然後經過CPU計算處理為多維圖形,在通過 OpenGL 調用GPU,GPU對圖形進行柵格化顯示 ...
  • 在做項目的過程中,使用正則表達式來匹配一段文本中的特定種類字元,是比較常用的一種方式,下麵是對常用的正則匹配做了一個歸納整理。 1、匹配中文:[\u4e00-\u9fa5] 2、英文字母:[a-zA-Z] 3、數字:[0-9]4、匹配中文,英文字母和數字及下劃線:^[\u4e00-\u9fa5_a- ...
  • 1.什麼是JQuery。 JavaScript開發的過程中,處理瀏覽器的相容很複雜而且很耗時,於是一些封裝了這些操作的庫應運而生。這些庫還會把一些常用的代碼進行封裝。 把一些常用到的方法寫到一個單獨的js文件,使用的時候直接去引用這js文件就可以了。(animate.js、common.js) 常見 ...
  • bootstrap中的導航條 一、和導航的區別 1. 導航條比導航多了一個條字 2. 直接上圖 導航: 導航條: 簡單文字描述: 由兩張圖看出,導航內容比較簡單,而導航條可以包含導航及其他元素,如表單,搜索框等,並且通常導航條會有一個區別於頁面的背景色。 二、在頁面中定義導航條 方法: 為父容器添加 ...
  • 前端之CSS2,內容包括 CSS盒子模型, 塊元素-內聯元素-內聯塊元素 ,浮動,定位,background屬性。其中,CSS盒子模型 包括 CSS盒子模型介紹,設置邊框,設置內間距padding,設置外間距margin,margin相關技巧,外邊距合併問題,margin-top 塌陷問題,元素溢出... ...
  • 1.計算屬性 我們可以將同一函數定義為一個方法而不是一個計算屬性。兩種方式的最終結果確實是完全相同的。然而,不同的是計算屬性是基於它們的依賴進行緩存的。只在相關依賴發生改變時它們才會重新求值;多次調用,計算屬性會立即返回之前的計算結果,而不必再次執行函數。 2.使用偵聽器 我們發現,與計算屬性相比, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...