iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 13
0
Modern Web

資料視覺化!D3入門到實戰系列 第 13

Day13 實戰!台灣各城市天氣概況_圖表hover提示

  • 分享至 

  • xImage
  •  

昨天我們幫圖表加上了一點進場動畫,因為座標軸沒有明確的數字,所以我們今天要加上hover圖表的提示(tooltip),也多了一點互動效果。

設計稿標示文件:https://yuanchen1103.github.io/2020ironman-weather-design/

實作思路

看著設計稿卻沒有靈感要如何實作嗎?先觀察一下設計圖並拆解一下:

這個東西可拆成

  • 直的虛線
  • 白色區塊
    • 綠色圓形
    • 數字

那要怎麼讓這個東西出現呢?我們希望滑鼠在hover上紅框的範圍都能觸發tooltip,所以我們可以建立好幾個透明的長方形,在hover上不同長方形的時候觸發畫出tooltip的事件。

製作觸發區塊

首先我們先來做觸發事件的區塊。

在那之前先去把之前長條圖的rect加上class,並改用class做選擇d3.selectAll('rect') => d3.selectAll('.bar'),才不會跟現在要新增的方形打架。

觀察一下上面那個圖,一個區塊的寬度為
柱體的寬度 + 2 * (1 / 2 * 間距) = 柱體的寬度 + 間距 = step

高度很簡單為chartHeight,知道了就開始畫圖吧~

g
    .selectAll('.hover-block')
    .data(data)
    .enter()
    .append('rect')
    .attr('class', 'hover-block')
    .attr('width', x.step)
    .attr('height', chartHeight)
    .attr('fill', 'transparent')
    //x為柱體的x 減 二分之一間距
    .attr('x', d => x(d.name) - ((x.step() - x.bandwidth()) / 2))
    // 加上滑鼠監聽事件
    .on('mouseover', (d, i) => {
      console.log(d, i); // 用console來測試看看
    });

摁!看起來沒什麼問題。再來只剩下放上tooltip了,tooltip因為一次只會出現一組,所以都只要各做一個就行,到時候再動態改變位置跟內容。
首先先加上黑色虛線:

const dashLine = g
    .append('line')
    .attr('class', 'dash-line')
    .attr('y1', 0)
    .attr('y2', chartHeight)
    .attr('stroke', '#454545')
    .attr('stroke-width', 1)
    .attr('stroke-dasharray', 8)
    .attr('opacity', 0); // 一開始先藏起來

再來加上訊息框,因為這個訊息框內容比較複雜,加上svg裡面的元素要加上陰影比較麻煩,所以我們這邊直接用div呈現,記得要加在<svg/>的外面,不然會無法顯示:

// 先在svg外的div加上position relative的style,這樣等一下我們才能在裡面用absolute做定位
<template>
  <div :id="`line-chart-${id}`" style="position: relative;"></div>
</template>
const messageWrapper = d3
    .select(`#line-chart-${this.id}`)
    .append('div')
    .html()
    .attr('class', 'message-wrapper') //指定class以後直接去css寫樣式比較快
    //在div裡面先寫好html,data是我們之後要塞數字的地方
    .html('<div class="circle"></div><div class="data"></div>')
    .attr('style', 'display: none;'); // 一開始先藏起來

再來就是重頭戲,剛剛我們不是有做好一個監聽事件嗎?在那裡面把tooltip內容定好並顯示就完成囉~

.on('mouseover', (d, i) => {
  dashLine
    .attr('x1', () => x(d.name) + x.bandwidth() / 2) //設定虛線位置
    .attr('x2', () => x(d.name) + x.bandwidth() / 2)
    .attr('opacity', 1); //顯示虛線

  d3.select('.message-wrapper .data').html(`${d.value} mm`); //塞進data value

  messageWrapper
    .attr('style', () => `display: flex; left: ${x(d.name) + 30}px`); //設定div位置並顯示
})
.on('mouseleave', (d, i) => {
  dashLine.attr('opacity', 0);
  messageWrapper.attr('style', 'display: none;');
});

終於把這個圖表完成了~其實只要把設計圖一個一個拆解開就不會覺得很複雜,我自己覺得畫d3最麻煩的地方就是在算那些x跟y的位置,仔細思考過後也沒有那麼難喔!

明天開始就會開始做折線圖,有了這個基礎以後是小case啦


今日進度commit: https://github.com/yuanchen1103/2020ironman-weather/commit/d643916e3a084b8be08ad8a4bb2df1defba69c76


上一篇
Day12 實戰!台灣各城市天氣概況_為長條圖加上動畫效果
下一篇
Day14 實戰!台灣各城市天氣概況_折線圖實作
系列文
資料視覺化!D3入門到實戰30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言