D3的全稱是Data-Driven Documents(數據驅動的文檔),是一個用來做數據可視化的JavaScript函數庫,而JavaScript文件的后綴通常為.js,所以D3被稱為D3.js。
d3.js可以定制出各種圖形,今天來用d3.js制作一個簡易的儀表盤,廢話不多說先上demo,接下來分步講解。
1.繪制svg,并分組(group)
const height = 600; //畫布高度 const width = 1200; //畫布寬度 const outerRadius = 200; //儀表盤外半徑 const innerRadius = 190; //儀表盤內半徑 const svg = d3.select('body').append('svg').attr('width', width).attr('height', height).style('background', '#000000'); // 在body中添加寬高并繪制背景色 const group = svg.append('g').attr('class', 'group').attr('transform', `translate(${width * 0.5}, ${height * 0.5})`); //添加分組并將分組中心移至畫布中心 const arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius) //編寫弧生成器并傳入內外半徑 const keduListB = [0,1,2,3,4,5,6,7,8,9,10,11,12]; //(大)刻度的數組 const keduListS = [0,1,2,3,4,5,6,7,8,9,10,11]; //(小)刻度的數組 const radiusScaleB = d3.scaleLinear().domain([0, 12]).range([Math.PI * (- 2 / 3), Math.PI * 2 / 3]) //(大)刻度線性比例尺 const radiusScaleS = d3.scaleLinear().domain([0, 11]).range([Math.PI * (- 11 / 18), Math.PI * ( 11 / 18 )]) //(小)刻度線性比例尺 let baseData = 0; //設置基礎速度
2.將內容分組
group.append('g').attr('class', 'pan') //繪制儀表盤的圓弧分組 group.append('g').attr('class', 'kedu_b') //繪制大刻度分組 group.append('g').attr('class', 'kedu_s') //繪制小刻度分組 group.append('g').attr('class', 'zhizhen') //繪制指針分組 group.append('g').attr('class', 'shuzi') //繪制刻度數字分組 group.append('g').attr('class', 'show') //繪制速度框和數字分組 group.append('g').attr('class', 'button') //繪制按鈕框和數字分組
3.繪制儀表盤的圓弧
group.select('.pan').append('path').attr('d', arc({startAngle: radiusScaleB(0),endAngle: radiusScaleB(12)})).attr('fill', '#6AE3F8').attr('stroke', '#6AE3F8');
4.繪制大刻度
group.select('.kedu_b').selectAll('line').data(keduListB).enter().append('line').attr('x1', d => 200 * Math.sin(radiusScaleB(d))).attr('y1', d => 200 * Math.cos(radiusScaleB(d)) * -1).attr('x2', d => 176 * Math.sin(radiusScaleB(d))).attr('y2', d => 176 * Math.cos(radiusScaleB(d)) * -1).attr('stroke', '#6AE3F8').attr('stroke-width', 5)
5.繪制小刻度
group.select('.kedu_s').selectAll('line').data(keduListS).enter().append('line').attr('x1', d => 200 * Math.sin(radiusScaleS(d))).attr('y1', d => 200 * Math.cos(radiusScaleS(d)) * -1).attr('x2', d => 180 * Math.sin(radiusScaleS(d))).attr('y2', d => 180 * Math.cos(radiusScaleS(d)) * -1).attr('stroke', '#6AE3F8').attr('stroke-width', 2)
6.繪制刻度數字
group.select('.shuzi').selectAll('text').data(keduListB).enter().append('text').attr('x', d => 160 * Math.sin(radiusScaleB(d))).attr('y', d => 160 * Math.cos(radiusScaleB(d)) * -1).attr('text-anchor', 'middle').attr('dy', '0.35em').attr('fill', '#6AE3F8').style('text-shadow', '0px 0px 2px #6AE3F8').text(d => d * 20)
7.繪制指針
group.select('.zhizhen').append('polygon').attr('points', '-2,-20,2,-20,4,0,1,140,-1,140,-4,0').attr('fill', '#6AE3F8').attr('transform', 'rotate(60)')
8.繪制速度框和數字
group.select('.show').attr('transform', 'translate(0, 100)').append('rect').attr('x', -60).attr('y', 0).attr('width', 120).attr('height', 40).attr('fill', 'none').attr('stroke', '#6AE3F8').attr('stroke-width', 3) group.select('.show').append('text').attr('text-anchor', 'middle').attr('x', 0).attr('y', 20).attr('dy', '0.35em').attr('fill', '#6AE3F8').attr('stroke', '#6AE3F8').attr('font-size', '20px').text(`0 km/h`)
9.繪制按鈕框和數字
d3.select('.button').append('rect').attr('x', -50).attr('y', 250).attr('width', 100).attr('height', 40).attr('fill', 'none').attr('stroke', '#6AE3F8').attr('stroke-width', 2)d3.select('.button').append('text').attr('x', 0).attr('y', 270).attr('text-anchor', 'middle').attr('dy', '.35em').attr('fill', '#6AE3F8').attr('font-size', '20px').text('加速')
10.速度不斷減小,并且點擊“加速”持續加速
d3.select('.button').attr('cursor', 'pointer').on('click', () => {if (baseData < 220) {baseData += 20change()} else if (baseData < 240) {baseData = 240;change()}}) setInterval(() => {if (baseData > 10) {baseData -= 10;change();} else if (baseData > 0) {baseData = 0;change()} }, 2000)
11.控制加速的方法(指針旋轉,速度數字增加)
const change = () => {group.select('.zhizhen').transition().duration(2000).ease(d3.easeLinear).attrTween('transform', function () {this._before = typeof this.getAttribute('transform') == 'string' ? this.getAttribute('transform').match(/\d+/g)[0] : 0;this._after = baseData;console.log('this._before',this._before)console.log('this._after',this._after)let interpolate = d3.interpolate(this._before, this._after);return function(t) {texts(interpolate(t))return `rotate(${interpolate(t)})`};})}const texts = text => {group.select('.show').select('text').attr('text-anchor', 'middle').attr('x', 0).attr('y', 20).attr('dy', '0.35em').attr('fill', '#6AE3F8').attr('stroke', '#6AE3F8').attr('font-size', '20px').text(`${Math.floor(text)} km/h`) }
這樣點擊加速就會調用change()方法,而change()方法在過渡是就會調用texts()方法。
這樣子就好了,一個基本的儀表盤就繪制好了
?
原創博客:轉載請注明d3.js 入門指南 - 儀表盤