1. 程式人生 > >vue整合d3.v5.js制作折線圖

vue整合d3.v5.js制作折線圖

set font prop atm dataset func return 圖片 arch

先上效果圖(x軸固定為時間軸):

技術分享圖片

圖中出現的懸浮框是鼠標懸停效果

1、環境說明:

vue版本:"vue": "^2.5.2"
d3版本:"d3": "^5.9.1"

2、Line.vue源碼

  1 <template>
  2   <div class="line" :id="id">
  3   </div>
  4 </template>
  5 
  6 <script>
  7   import * as d3 from d3
  8   export default {
  9
name: line, 10 props: { 11 id: String, 12 width: Number, 13 height: Number, 14 dataset: Array 15 }, 16 mounted() { 17 this.init(); 18 }, 19 methods: { 20 init() { 21 d3.select("#svg" + this.id).remove(); 22
let width = this.width ? this.width : 600; 23 let height = this.height ? this.height : 600; 24 let padding = { 25 left: 80, 26 right: 50, 27 top: 50, 28 bottom: 50 29 } 30 let colorZ = d3.scaleOrdinal(d3.schemeDark2)
31 let parseTime = d3.timeParse("%Y-%m-%d") 32 let xScale = d3.scaleTime().range([0, width - padding.left - padding.right]) 33 let dates = this.dataset.flatMap((d) => d.value.map(v => parseTime(v.key))) 34 xScale.domain([d3.min(dates), d3.max(dates)]) 35 let yScale = d3.scaleLinear().range([height - padding.top - padding.bottom, 0]) 36 yScale.domain([0, d3.max(this.dataset.flatMap((d) => d.value.map( v => v.value) )) + 2]) 37 let xAxis = d3.axisBottom(xScale).tickFormat(d => d.getFullYear() + - + (d.getMonth() + 1) + - + d.getDate()) 38 let yAxis = d3.axisLeft(yScale) 39 let svg = d3.select("#" + this.id).append("svg").attr("width", width).attr("height", height).attr("id", "svg" + this.id); 40 svg.append(g) 42 .attr(transform, translate( + padding.left + , + (height - padding.bottom) + )) 43 .call(xAxis) 44 .selectAll(text) 45 .attr(dx, -20) 46 .attr(dy, 10) 47 .attr(transform, rotate(-20)) 48 .style(font-weight, bold) 49 svg.append(g) 51 .attr(transform, translate( + padding.left + , + padding.top + )) 52 .call(yAxis) 53 .selectAll(text) 54 .style(font-weight, bold) 55 let line = d3.line().x(d => xScale(parseTime(d.key))).y(d => yScale(d.value)) 56 this.dataset.forEach((v, vi) => { 57 let tp_x = 0, 58 tp_y =0; 59 svg.append("path") 60 .attr(d , line(v.value)) 61 .attr(transform, translate( + padding.left + , + padding.top + )) 62 .attr(fill, none) 63 .attr(stroke, (d, i) => colorZ(vi)) 64 .attr("stroke-width", 2) 65 .style(stroke-dasharray, function(d, i) { 66 return d3.select(this).node().getTotalLength(); 67 }) 68 .style(stroke-dashoffset, function(d, i) { 69 return d3.select(this).node().getTotalLength(); 70 }) 71 .transition() 72 .duration(2000) 73 .ease(d3.easePolyOut) 74 .delay((d, i) => i * 200) 75 .style(stroke-dashoffset, 0) 76 svg.selectAll(circle1) 77 .data(v.value) 78 .enter() 79 .append(circle) 80 .attr(cx, (d, i) => { 81 let x = xScale(parseTime(d.key)) 82 if (i === v.value.length - 1) tp_x = x - 40 83 return x 84 }) 85 .attr(cy, (d, i) => { 86 let y = yScale(d.value) 87 if (i === v.value.length - 1) tp_y = y - 10 88 return y 89 }) 90 .attr(r, 2) 91 .attr(transform, translate( + padding.left + , + padding.top + )) 92 .style("fill", (d, i) => colorZ(vi)) 93 .on("mouseover", (d, i) => { 94 let g = svg.append(g) 95 .attr(id, `hoverg${vi}${d.key}${d.value}`) 96 .attr("transform", "translate(" + (xScale(parseTime(d.key)) - 20) + "," + (yScale(d.value) + 30) + ")" ) 97 g.append("rect") 98 .attr("x", function(d){ return this.parentNode.getBBox().x - 3;}) 99 .attr("y", function(d, i){ return this.parentNode.getBBox().y - 20}) 100 .attr("width", 110) 101 .attr("height", 25) 102 .style("fill", "#fffbf0") 103 g.append(text) 104 .text(`${d.key}:${d.value}`) 105 .style("fill", colorZ(vi)) 106 }) 107 .on("mouseout", (d) => d3.select(`#hoverg${vi}${d.key}${d.value}`).remove()) 108 .transition() 109 .duration(1500) 110 .ease(d3.easePolyIn) 111 .delay((d, i) => i * 200) 112 .attr(r, 5) 113 // svg.selectAll(‘text1‘) 114 // .data([v.name]) 115 // .enter() 116 // .append(‘text‘) 117 // .attr(‘dx‘, (d, i) => tp_x) 118 // .attr(‘dy‘, (d, i) => tp_y) 119 // .attr(‘transform‘, ‘translate(‘ + padding.left + ‘,‘ + padding.top + ‘)‘) 120 // .text((d) => d) 121 // .style("fill", (d, i) => colorZ(vi)) 122 // .style(‘font-weight‘, ‘bold‘) 123 svg.append(text) 124 .attr(dx, tp_x) 125 .attr(dy, tp_y) 126 .attr(transform, translate( + padding.left + , + padding.top + )) 127 .text(v.name) 128 .style("fill", colorZ(vi)) 129 .style(font-weight, bold) 130 }) 131 } 132 }, 133 watch: { 134 dataset() { 135 this.init(); 136 } 137 } 138 } 139 </script> 140 141 <style> 142 143 </style>

3、使用示例

 1 <template>
 2   <div id="test">
 3     <!-- 一定要傳進去一個id,隨便傳一個 -->
 4     <line id="line" :dataset="data1"></line>
 5   </div>
 6 </template>
 7 
 8 <script>
 9   import line from @/components/d3/Line
10   export default {
11     name: test,
12     data() {
13       return {
14         data1: [
15           {
16             name: 哈爾濱,
17             value: [{key: 2015-1-1, value: 10}, {key: 2015-1-2, value: 12}, {key: 2015-1-3, value: 13}, {key: 2015-1-17, value: 17}]
18           },
19           {
20             name: 海南,
21             value: [{key: 2015-1-1, value: 9}, {key: 2015-1-2, value: 48}, {key: 2015-1-3, value: 5}, {key: 2015-1-17, value: 49}]
22           },
23           {
24             name: 天津,
25             value: [{key: 2015-1-2, value: 30}, {key: 2015-1-3, value: 1}, {key: 2015-1-4, value: 32}, {key: 2015-1-5, value: 10}]
26           }
27         ]
28       }
29     },
30     components: {
31       line
32     },
33     methods: {
34 
35     }
36   }
37 </script>
38 
39 <style scoped>
40 </style>

4、參考資料

https://github.com/d3/d3-scale-chromatic/blob/master/README.md#schemeCategory10

https://github.com/d3/d3-time-format#format

https://jakearchibald.com/2013/animated-line-drawing-svg/

vue整合d3.v5.js制作折線圖