iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 21
0
Modern Web

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

Day21 實戰!Github Heat Map 產生器_Heat Map實作(2)

昨天我們把熱力圖需要的正方形擺得整整齊齊的,那接下來就是熱力圖最重要的部分:把區塊上色。
在實作之前,我們先來理解一下要如何使用d3做色彩的管理。

網頁色彩

顏色絕對是設計不可或缺的一部分,我們在寫css style時也常常使用到顏色,最常使用的是hex及rgba,那麼色碼到底是什麼?
首先是rgb色彩,國中小的自然課都有學到,光的三原色為紅、綠、藍,分別代表的就是r、g、b。
https://ithelp.ithome.com.tw/upload/images/20190920/20119937SnneIfZKn1.png

而我們在設定rgb色彩時,都會分別填入0~255的數值rgb(0-255, 0-255, 0-255),這些數值代表的意義很簡單,就是色光的強度,0就是燈沒開,255的燈就是全開的。因此rgb(0, 0, 0)就是三色燈都沒開=黑色;rgb(255, 255, 255)就是三色燈全開=白色。

那rgba中的a又是什麼,a為Alpha(色彩空間),以應用面來看為不透明度參數,0是完全透明、100則是完全不透明。

下一個是hex色碼,也就是我們常看到的#加上六個字母or數字,這幾個字代表的意義很容易,前兩個為紅色、中間兩個為綠色,最後兩個是藍色,意義與rgb完全相同,00是全關,FF為全開,此為十六進位制(0,1,2....a,b,c...f)。

d3中的色彩

有了色彩的知識以後,我們現在知道那些數字、字母都是有意義的,也就是說可以被量化,而d3就是利用這個原理去管理、調整色彩的。例如brighter、darke的funciton可以讓顏色變亮變暗,也可以應用在scale當中去計算特定的漸層顏色,我們今天就是用這個方式去產生Heat Map中每個數值所轉換出來的色彩。

d3 color的api文件:https://github.com/d3/d3-color

實作

我們現在就來幫昨天做完的方形們塗上顏色

const colorScale = d3.scaleLinear()
    .domain([0, d3.max(data.map((e) => e.value)) / 2, d3.max(data.map((e) => e.value))])
    // 我這邊的間層色有三個色彩點,分別代表0, 正中間的數值, 最大的數值
    .range(['#F3F3F3', '#84B6FD', '#8E87FA']);

g.selectAll('.block')
    .data(data)
    .enter()
    .append('rect')
    .attr('class', 'block')
    .attr('x', (d) => (d.weekNum - 1) * 15 + (d.weekNum - 1) * 1)
    .attr('y', (d) => d.day * 15 + d.day * 1)
    // 超簡單,一樣直接value塞進去
    .attr('fill', (d) => colorScale(d.value))
    .attr('width', 15)
    .attr('height', 15)
    .attr('rx', 3);

https://ithelp.ithome.com.tw/upload/images/20190920/20119937KEr0eTwgG3.png

再來標上座標就完成熱力圖囉,感覺比長條圖更簡單~

const days = [0, 1, 2, 3, 4, 5, 6];

g
    .selectAll('.day-label')
    .data(days)
    .enter()
    .append('text')
    .attr('class', 'day-label')
    .text((d) =>
      moment()
        .isoWeekday(d)
        .format('ddd') //星期的前三個字
    )
    .attr('font-size', 8)
    .attr('fill', '#B8B8B8')
    .attr('opacity', (d, i) => (i % 2 === 0 ? 1 : 0)) //index是奇數才顯示
    .attr('x', -20)
    .attr('y', (d, i) => i * 15 + i * 1 + 9);

const monthFirstDays = data.filter(e => e.date.substring(8, 10) === '01');
// 抓出每個月第一天的data

g
    .selectAll('.month-label')
    .data(monthFirstDays)
    .enter()
    .append('text')
    .attr('class', 'month-label')
    .text((d) =>
      moment(d.date)
        .format('M')
    )
    .attr('font-size', 8)
    .attr('fill', '#B8B8B8')
    .attr('text-anchor', 'middle')
    .attr('x', (d) => (d.weekNum - 1) * 15 + (d.weekNum - 1) * 1 + 7.5)
    .attr('y', -5);

https://ithelp.ithome.com.tw/upload/images/20190920/20119937hc6RZuTK10.png


上一篇
Day20 實戰!Github Heat Map 產生器_Heat Map實作(1)
下一篇
Day22 實戰!Github Heat Map 產生器_熱力圖的進場動畫
系列文
資料視覺化!D3入門到實戰30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言