今天要來練習用 D3
搭配 Vue
做簡易的 SVG
橫條圖囉~
上一篇有描述過:
準備 SVG
畫布
準備隨機資料
加上提示資料的 tooltip
這幾個部分大同小異,所以這裡就不再次解釋,我們直接從處理座標軸開始說起。
插入座標軸
1 2 3 4 5 6
| <g :transform="`translate(0, ${chart.height})`" class="axis axisX" fill="none" font-size="10" font-family="sans-serif" text-anchor="middle"></g>
<g class="axis axisY" fill="none" font-size="10" font-family="sans-serif" text-anchor="end"></g>
<text class="axisYText" :x="axisYText[0]" :y="axisYText[1]" dy="1em" text-anchor="middle">件數</text>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| .chart { ...... .chartWrap { .axis.axisX { .domain { display: none; } .tick { line { stroke: #efefef; stroke-width: 2; stroke-dasharray: 1, 6; stroke-linecap: round; } } } } }
|
因程式碼過多,這邊只講用到的 D3 函數部分,文章最後會有完整程式碼連結。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| xScale() { let Xmin = 0; let Xmax; let newArray = [];
this.data.value.forEach(function(e) { newArray.push(e.number); }); Xmax = d3.max(newArray);
return d3 .scaleLinear() .domain([Xmin, Xmax]) .range([0, this.chart.width]); },
xAxis() { return d3 .axisBottom(this.xScale) .tickSizeInner(-this.chart.width); },
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| yScale() { return d3 .scaleLinear() .domain([0, this.data.value.length + 1]) .range([this.chart.height, 0]); },
yAxis() { let tickNum = this.valueLength < 3 ? this.valueLength + 1 : this.valueLength;
return d3 .axisLeft(this.yScale) .ticks(tickNum) .tickFormat((d, i) => { return this.yLabel[i]; }); },
|
在每次隨機資料後,動態插入座標軸。
1 2 3 4 5 6 7 8 9 10 11
| randomData() { ...... document.querySelector(".chart .axisX").innerHTML = ""; document.querySelector(".chart .axisY").innerHTML = "";
d3.select(".chart .axisX").call(this.xAxis); d3.select(".chart .axisY").call(this.yAxis); },
|
繪製橫條
1 2 3 4
| <transition-group tag="g" name="growBarp"> <rect class="bar" v-for="(rect, key) in bar" :key="`${key}${rect.width}${rect.y}`" :fill="rect.color" :x="rect.x" :y="rect.y" :width="rect.width" :height="rect.height" v-on:mouseover="showTooltip(key, $event)" v-on:mouseout="hiddenTooltip"></rect> </transition-group>
|
1 2 3 4 5 6 7 8
| .growBarp-enter-active { transition: all 1s; } .growBarp-enter { transform: scaleX(0); opacity: 0; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| color() { return d3.scaleOrdinal(d3.schemeCategory10); },
barWidth() { let gap = 20;
return this.chart.height / (this.valueLength + 1) - gap; },
bar() { let rectArray = [];
if (this.data.value) { this.data.value.forEach((e, i) => { rectArray.push({ color: this.color(0), x: 0, y: this.yScale(i + 1) - this.barWidth / 2, width: this.xScale(e.number), height: this.barWidth }); }); }
return rectArray; },
barText() { let textArray = [];
if (this.data.value) { this.data.value.forEach((e, i) => { textArray.push({ x: this.xScale(e.number) - 20, y: this.yScale(i + 1) + 5, number: e.number }); }); }
return textArray; }
|
全部畫好的樣子如下圖,可以去 Github 查看完整程式碼喔!也可以在這裡查看橫條圖的 Demo,我們下回見~