~~~ L O A D I N G ~~~~~ L O A D I N G ~~~~~ L O A D I N G ~~~

學到新資視了 - Highcharts / 日期座標軸&語言設定

Sep 29, 2020 Max Lee

本章節範例:https://codepen.io/max-lee/pen/GRZwKjW

今天要又要來填坑了,在座標軸設定時有說會特別介紹「日期座標軸」,因為它的設定不僅僅與「座標軸設定」有關,還必須連動「數據列設定」,並且搭配昨天介紹的「格式化屬性」,算是比較複雜的應用。


另外今天還會提到「語言設定」,它可以讓我們定義一些因 地區習慣 不同而變化的預設字符,包含昨天的千份位符號以及今天會用到的月份、星期名稱...等等。


日期座標軸

當圖表的資料是包含時間維度的,那就有使用「日期座標軸的」需求,用來標示個別數據點的測量/紀錄時間。

而在 座標軸設定 介紹過了,只要將 Axis.type 設為 datetime 即可將座標軸設定為「日期座標軸」。

var myChart = Highcharts.chart(container, {
  title: { text: "臺北市每日氣溫" },
  subtitle: { text: "2020年9月第一週" },
  credits: { enabled: false },
  xAxis: {
    type: "datetime"
  },
  yAxis: {
    title: { text: "攝氏溫度" },
    labels: { format: "{value}°C"}
  },
  series: [{
    name: "平均溫度",
    data: [30, 30, 31, 28, 29, 29, 28]
  }]
});

但如果僅僅只是這樣設定,你會發現座標軸的刻度與 每日氣溫 這個圖表主題不太相符,因為「日期座標軸」預設是以 1970/1/1 作為數據點的起始值,並且間距為 1毫秒。那下面我們就以完成這張圖表為目標,一步步學習如何設定「日期座標軸」吧。


# 調整座標刻度間距

首先,我們先將座標刻度的間距改為「一天」,這裡要運用的屬性是 Axis.tickInterval,之前在 座標軸設定 裡一樣有介紹過。

xAxis: {
  type: "datetime",
  tickInterval: 24 * 3600 * 1000 // 一天的毫秒數
},

設定完之後會發現座標刻度都消失了,只剩下一個 1.Jan,因為雖然刻度間距已經調整為一天了,但數據點之間的時間間隔還是被 Highcharts 認定為是 1毫秒。所以對圖表來說,這七個點都是同一天的數據,自然也就不需要顯示第二天、第三天的刻度了。


# 調整數據點間距

為了解決上面的問題,要利用之前在 數據點設定 中提過的 series.pointInterval 來將數據點的間距改為一天。

series: [{
  name: "平均溫度",
  data: [30, 30, 31, 28, 29, 29, 28],
  pointInterval: 24 * 3600 * 1000 // 一天的毫秒數
}]

這樣座標刻度與數據點就對上了,剛好一天一個點,不過目前的起始X軸座標還是 1970/1/1,所以接下來要將日期改成我們要的九月第一週。


# 調整數據點起始X值

由於我們設定數據點資料的方式是「數值設定法」,所以數據點本身沒有X軸數值,使得 Highcharts 以 1970/1/1 零毫秒 作為我們第一個數據點的起始X軸數值,所以我們要用 series.pointStart 來將數據點的起始設定為 8/31,也就是九月第一週的星期一。

series: [{
  name: "平均溫度",
  data: [30, 30, 31, 28, 29, 29, 28],
  pointStart: new Date("2020/8/31").getTime(),
  pointInterval: 24 * 3600 * 1000 
}]

在使用日期座標軸的圖表中,數據點X軸數值是以「時間戳數值」來表示的,所以我們只要傳入 2020/8/31 這一天的時間戳數值即可。

但如此設定後,卻發現數據點發生了偏移,而且看了一下第一個數據點的提示框,發現起始點竟然不是 2020/8/31 而是 2020/8/30 16:00,原來 Highcharts 是以格林威治的時間來計算的,但 new Date() 拿到的是台灣本地時間,所以才會早了八個小時。


台灣的時區是 GMT+8,比格林威治標準時間快八個小時。所以在台灣進入 2020/8/31 00:00 時,格林威治還在 2020/8/30 16:00


# 調整時區的時間差

為了讓圖表的數據點時間點和刻度可以對得起來,就要處理因為時區所造成的時間差,這裡有兩種方法提供給大家。

你可以使用「時間設定」裡的 time.timezoneOffset 來告訴 Highcharts 你的時區偏移隔離威治多少,而這個數值可以透過 getTimezoneOffset 這個日期方法來取得。

let offset = new Date().getTimezoneOffset(); // -480

var myChart = Highcharts.chart(container, {
  time: { timezoneOffset: offset }
});

或是比較簡單的做法是以 Date.UTC 來取得時間戳數值,而非 new Date(),因為它可以直接取得國際標準時間的時間戳。

series: [{
  name: "平均溫度",
  data: [30, 30, 31, 28, 29, 29, 28],
  pointStart: Date.UTC(2020, 7, 31),
  pointInterval: 24 * 3600 * 1000 
}]

如此一來,我們就有一個時間完全正確的圖表了。


# 指定時間的數據點

雖然目前的成果基本滿足需求,但假如 9/3 中午12:00 有一個歷年高溫我們想要加到圖表中,那該怎麼辦?

由於我們已經利用 pointStart 設定了數據點間隔,如果從中穿插一個點,只會讓圖表多增加一天而已,所以在加入這個數據點時,我們要直接為它指定時間戳在X軸數值。

let specifyPoint = {
  x: new Date("2020/9/3 12:00").getTime(),
  y: 36,
  color: "red",
  custom: "中午12:00"
} 

var myChart = Highcharts.chart(container, {
  series: [{
    name: "平均溫度",
    data: [30, 30, 31, 28, specifyPoint, 29, 29, 28],
    pointStart: new Date("2020/8/31").getTime(),
    pointInterval: 24 * 3600 * 1000 
  }]
});

這樣就可以有指定時間的數據點了,另外,其實你也可以不用 pointStartpointInterval,完全使用指定的X軸數值來製作日期座標軸圖表。


# 語言設定

到這裡,我們的溫度圖表已經完全可以拿來提供給使用者觀看了,可是看著英文的月份和星期實在是有點不親切,為了改變這些 Highcharts 預設的字符,必須使用全域的「語言設定」。

Highcharts.setOptions({
  lang: {
    months: ['一月', '二月', .... '十二月'], // 中間省略
    shortMonths: ['1月', '2月', .... '12月'], // 中間省略
    weekdays: ["星期一","星期二", .... "星期日"] // 中間省略
  }
})

var myChart = Highcharts.chart(container, {
  //...省略
});

程式碼中可以看到一個新的方法 Highcharts.setOptions,它是用來設定全域設定的,影響範圍是頁面中的全部圖表,所以只要設定一次即可。其中「語言設定」必須使用這個方式來定義,這裡我們將月份和星期改成中文的版本。

如此一來,刻度標籤和提示框就有親切的中文顯示囉~

另外昨天提到的小數點與千分位符號也是在「語言設定」中調整的。

lang: {
  decimalPoint: ".", // 小數點預設值
  thousandsSep: "\u0020" // 千分位預設值,\u0020 為空白符號
}

# 日期格式化

雖然已經有中文了,不過日期的字串格式似乎不太符合台灣人的習慣,這時候就可以運用昨天才學到的格式化屬性來調整了,而且 Highcharts 一樣有提供日期的特殊符號可以使用。

var myChart = Highcharts.chart(container, {
  yAxis: {
    title: { text: "攝氏溫度" },
    labels: { format: "{value}°C"}
  },
  tooltip: {
    headerFormat: "{point.key:%Y/%m/%d %A}<br/>",
    pointFormatter() {
      let type =  this.custom ? "最高溫度" : "平均溫度";
      let time = this.custom ? `(${this.custom})` : "" ;
      return `${type}: ${this.y}°C ${time}`
    }
  },
});

最後把上面的符號表規則應用在昨天學到的格式化屬性後,我們就有一個非常完美的客製化圖表了,同時也把「日期座標軸」的設定方法和應用搞清楚了。


今天利用了一整個範例來學習「日期座標軸」,並且成功製作了一個包含時間維度的圖表,相信未來如果有類似需求,各位應該可以易如反掌得解決了。而明天要繼續跟大家介紹的是「主題設定」。


- 此篇文章為「iT邦幫忙鐵人賽」參賽文章,同步發表於 iT邦幫忙 -

Prev Post
Next Post