kuro's Blog

[Vue.js] 在 v-for 列表中透過 filter 完成搜尋與分頁的功能

| Comments

最近 Vue.js 正夯,所以手上幾個東西打算用這個來改寫,關於 Vue.js 的基本介紹可以參考小弟的投影片,這裡就不再贅述。

有用過 Vue.js 開發的朋友一定知道它提供的 filter 功能十分強大,在 v-for 列表中使用 filterBy 可以在一行內完成列表搜尋的功能:

  <div id="filter-by-example">
    <input v-model="n">
    <ul>
      <!-- 透過 input 欄位的 v-model n 與 user.name 做模糊比對 -->
      <li v-for="user in users | filterBy n in 'name'">
        {{ user.name }}
      </li>
    </ul>
  </div>

若是要限制顯示的筆數也能用 limitBy 做到,進而完成分頁的功能。

  <!-- 只顯示前 10 個元素 -->
  <div v-for="item in items | limitBy 10"></div>

  <!-- 顯示第 5 到 15 筆元素-->
  <div v-for="item in items | limitBy 10 5"></div>

這次遇到的問題是這樣的,如果我們想要同時完成「搜尋」與「分頁」的需求,光靠 filterBylimitBy 就不是那麼容易做到,還好 Vue.js 提供了自訂 filter 的功能,

<!-- 
  先用 filterBy 過濾,再透過自訂 recordLength 記錄過濾後的資料數量,最後再用 limitBy 搭配頁籤切換頁面。
  小心 filter 的順序,filter 會依序執行,然後再繼續下個 filter。
-->
  <tr v-for=" r in rows 
               | filterBy filter_name in 'name'     
               | recordLength 'filteredRowCount'    
               | limitBy countOfPage pageStart ">
        <td>......</td>
  </tr>

然後是自定的 filter recordLength
result 代表傳入的資料, key 則是從 view 帶入的參數,這個範例是 filteredRowCount
這裡透過 vm.$set 來將過濾後的數量指定至 vue 實體,以便可以直接在 Vue 實體使用。

  Vue.filter('recordLength', function (result, key) {
    this.$set(key, result.length);
    return result;
  });

最後在頁籤的部分,我們就可以簡單透過 filter_name 欄位是否空白來切換是否透過 filteredRowCount 計算總頁數:

  totalPage: function(){
    if( this.filter_name.trim() === '' ) {
      return Math.ceil(this.rows.length / this.countOfPage);
    }
    else{
      return Math.ceil(this.filteredRowCount / this.countOfPage);
    }
  }

完整的 demo 如下:
JS Bin on jsbin.com

利用 d3.js 製作 responsive 的長條圖

| Comments

利用 d3.js 我們可以很輕易地產生我們想要的圖表,以最常見的長條圖為例,只要透過 scale (比例尺) 與 axis (軸線),再加上一點 SVG 的基礎知識,像這樣的長條圖一下子就可以生成。

螢幕快照 2015-12-20 下午12.21.25.png
[Code]

但是,像這樣尺寸的圖表,往往都會因為太大而不適合在手機螢幕上呈現。還好 SVG 有著向量圖形的特性,可以自由縮放,這篇就來簡單介紹 d3.js 的長條圖如何也能做出 rwd 的效果。

在上面的程式碼內,我們可以看到,原先設定的寬高是寫死的 960 與 500 (未扣除邊界)

  var margin = 40,
      width = 960 - margin*2,
      height = 500 - margin*2;

所以第一步,我們先將外層的 .content 元素設定成寬高 100%,然後把原先寫死的寬高改成由程式去抓取實際的寬高

.content{
  display: block; width: 100%; height: 100%;
  min-width: 300px; max-width: 960px; max-height: 500px; overflow: hidden;
}
 // 將尺寸改成即時取得的寬高

 width = parseInt(d3.select(".content").style("width"), 10) - margin*2;
 height = parseInt(d3.select(".content").style("height"), 10) - margin*2; 

然後我們將瀏覽器縮小之後重整,結果像這樣:
螢幕快照 2015-12-20 下午1.23.36.png
[Code]

可以看到,這個時候因為畫面的寬高已經不是寫死的了,所以會依「繪製圖形當下」的寬高去做比例的修正。這時我們已經完成了長條圖 RWD 的第一步了。

這時要是將行動裝置螢幕橫擺後,比例並不會依照橫擺之後有所不同,如果要使用者不斷地重整頁面,這就太不友善了。所以,我們要在瀏覽器上加上 resize 事件,並將繪製圖形的動作通通封裝至 rendering 這個 function 內。

這個時候的程式架構會像這樣:

  var svg = d3.select('.svg');

  // 將繪製動作包裝至 function 內

  function rendering() {
     // 將繪製的程式碼通通搬到裡面

     // 內略

  }

  // 將 window 綁定 resize 事件,並重新繪製圖型

  d3.select(window).on('resize', rendering);

  // 首次繪製

  rendering();

所以,這個時候,我們可以任意拉放瀏覽器的尺寸
像這樣
螢幕快照 2015-12-20 下午1.39.54.png

或是這樣
螢幕快照 2015-12-20 下午1.40.01.png

[Code]
都是沒有問題的。

這份長條圖到目前為止已經可以說是好棒棒了。
可是不曉得有沒有人發現,在最後那張橫擺的 y 軸刻度實在太過擁擠,其實是不容易閱讀的:
螢幕快照 2015-12-20 下午1.42.43.png

我們可以怎麼樣更優化呢?

這時候就要利用 d3.js 提供的 tick() 功能,來為我們調整 y 軸上的刻度。
只要在 y 軸上加上 tick ,像這樣:

  // y 軸加上 ticks

  var yAxis = d3.svg.axis()
        .scale(yScale2)
        .orient("left")
        .ticks(Math.max(height/50, 2));

Math.max 會回傳兩個指定數字中較大的一個,而 ticks() 則是設定軸線上刻度的數量。

所以經過剛剛的設定,當圖形的高度大於 100px 的時候,圖表每 50px 會有一個刻度,而圖形高度小於或等於 100px 時,則至少會有兩個刻度,像這樣:

螢幕快照 2015-12-20 下午1.54.29.png

螢幕快照 2015-12-20 下午1.55.08.png

[Code]

實際用手機試試:

2015-12-20 03.33.30.png
2015-12-20 03.33.43.png

透過這樣的修正,就可以讓圖表變得更好閱讀了。

以上,我們只要做簡單的小調整,就可以讓現有的 d3 長條圖做到有 RWD 的效果。

但是要注意的是,不是所有圖表都合適在手機螢幕上呈現,在設計時也需要把這些考慮進去,是要為手機版本另外做一個新的圖表,或是做 RWD 的設計,就看使用的情境以及想表達的意義來決定囉。

利用 Google Fusion Table,不用寫 code 也可以產生主題地圖

| Comments

感謝台北市政府以及相關人士的努力,在十月中旬的時候,台北市 open data 平台又開放了「台北市住宅竊盜點位資訊」這樣的資料,雖然很多人戲稱房價又要下跌了,但是老話一句,身為有良心的開發者,當然居住安全比房價什麼的還要重要得多

那麼,拿到這份資料我們可以怎麼玩呢?
剛好這份資料的格式是 CSV (Comma-Separated Values,一種由逗點分隔的純文字資料格式),所以本篇就來介紹如何透過 Google Fusion Table 來讓我們不必寫任何的 code ,也可以建立主題地圖。

首先先到台北市住宅竊盜點位資訊,點一下「使用資料」將所需的檔案下載下來,會得到一份 csv 檔案。

螢幕快照 2015-10-15 上午10.16.22.png

接著打開 Google Fusion Table 的頁面,看到下面這個畫面:
螢幕快照 2015-10-15 上午10.33.31.png

接著選擇「CREATE A FUSION TABLE」,會看到這樣的畫面:
螢幕快照 2015-10-15 上午10.37.48.png

現在試著把剛剛的 csv 直接餵給他,看看會發生什麼事
螢幕快照 2015-10-15 上午10.05.47.png

如果不意外,你應該會得到像這樣的亂碼資料 XDDDDD
螢幕快照 2015-10-15 上午10.06.19.png

不過沒關係,山不轉路轉,檔案格式當然也可以轉。只是需要多走幾步路。
這次我們將原始的 csv 資料先丟到 Google Sheet 內,請他將我們的資料轉成正確的編碼。 在建立一個新的 Google Sheet 之後,我們選擇 File > Import 將剛剛的 csv 檔案匯入:
螢幕快照 2015-10-15 上午10.07.40.png

記得一樣要選擇 Comma,因為是透過逗點分隔的資料格式。
螢幕快照 2015-10-15 上午10.08.07.png

然後就會得到正確編碼後的資料囉。不過糖廍里一樣 GG...因為原始資料就 GG 了... orz
未命名.png

ok, 到了這裡我們已經有一份正確的資料,這時再回到 Funsion Table,我們選擇 「Google Spreadsheets」,然後將剛剛建立的 Google Sheet 匯入進來:
螢幕快照 2015-10-15 上午10.37.48.png

螢幕快照 2015-10-15 上午10.11.18.png

匯入成功後,Funsion Table 會出現這樣的畫面:
未命名.png

這個時候,因為我們要製作地圖,所以要告訴 Funsion Table 地點的欄位不是單純的字串,而是用來表示地理資訊的資料。點選 Edit > Change columns:
螢幕快照 2015-10-15 上午10.11.57.png

然後將發生地點的 Type 改成 Location,然後點上面藍色的 Save 儲存。
螢幕快照 2015-10-15 上午10.12.09.png

資料都準備好了,然後我們建立地圖:
螢幕快照 2015-10-15 上午10.58.53.png

不意外的話你應該會看到這樣的畫面,是因為我們傳入的是地址的文字資訊, Google 需要將它轉為經緯度後才能對應到地圖上:
螢幕快照 2015-10-15 上午10.13.03.png

然後等待一段時間後,Funsion Table 就會為我們產生地圖,像這樣:
螢幕快照 2015-10-15 上午10.20.02.png

除了地點標示外,他也提供了熱圖 (Heat Map) 的呈現,試著拉拉旁邊的捲軸調整參數吧:
螢幕快照 2015-10-15 上午11.03.53.png

當然你也可以做好的地圖 share 出來,像這樣:

透過 Fusion Table 我們可以不用寫任何的程式碼就生成一份資訊地圖,很簡單吧 :)

利用 Google Map 檢視台北市降雨淹水模擬圖

| Comments

看到前兩天的新聞: 柯文哲想公開易淹水地區 北市府已上網,又剛好有前輩寫了一篇 利用QGIS檢視台北市降雨淹水模擬圖雖然身處房仲業,但身為有良心的開發者不能只想著房價,心想應也可透過 Google Map 來呈現,於是試了一下,順便寫篇記錄。

首先從臺北市政府資料開放平台將所需的資料一一下載下來,格式是 kmz (其實就是 zip 壓縮)。在解壓縮後可以得到 doc.kml 檔案。 接著,雖然 Google maps API 有提供 KML Layers 的圖層嵌套,但轉出來的 kml 檔似乎要稍作修改後才能透過 KML Layers 套用在 Google map 上,這裏我選擇另一種做法: 將 kml 轉為 geoJSON 後使用。

前面說到要將 kml 檔案轉為 geoJSON,那麼該如何轉換格式呢?
幸好 mapbox 提供了 togeojson 這套工具,透過它提供的 toGeoJSON.kml(doc) 就可以輕鬆地將它轉為 geoJSON 的格式了。

有關 GeoJSON 如何輸出至 Google Map 可以參考小弟之前的 post:透過 Google Maps API 處理 GeoJSON 資料,這裏就不再贅述。

值得一提的是,透過 Google Maps Javascript API 輸出的 GeoJSON 預設的樣式都是黑色粗線,想要修改樣式的話可以透過 setStyle 來做處理,像這樣可以針對 name 是 0.3 的時候,我們輸出樣式為藍色的線,如果是 0.3~1.0 的話,則是輸出為綠色的線段,當然也可以針對填色與透明度等等做設定。

dataMap.setStyle(function(feature){
  if( feature.getProperty('name') === '0.3'){
    return { fillOpacity: 0.35, fillColor: '#0070FF', strokeWeight: 2, strokeColor: '#0070FF', strokeOpacity: 1 };
  }
  if( feature.getProperty('name') === '0.3~1.0'){
    return { fillOpacity: 0.35, fillColor: '#54FF00', strokeWeight: 2, strokeColor: '#54FF00', strokeOpacity: 1 };
  }
});

結果呈現像這樣:
image.png

這裏也有 Online Demo: http://kurotanshi.github.io/TPEDisasterSummary/rain/rain_tp_map.html

[筆記] JavaScript 變數宣告與作用域

| Comments

大家都知道,JavaScript 的變數有其作用域的範圍,若使用前未經 var 宣告,就會自動變成全域變數 (global variable),而在其 code block 內宣告的變數也只有該 code block 內可以使用。

這次的問題,其實很久以前在 tonyQ 的聚會上就聽他說過了,只是沒想到還真的會遇到 XDDDD

var a = 1;

(function(){
  console.log(a);      // 1

})();

上面的 code 很簡單,就是宣告一個全域變數 a,然後值為 1 ,因為是全域變數,所以在之後的匿名函式內可以使用它。

var a = 1;

(function(){
  var a = 100;
  console.log(a);      // 100

})();

這次,在匿名函式內,我們另外宣告了一個 a,值為 100,因為其作用域的關係,所以 console 的結果會是 100。

接著,問題來了,如果我們在 var a = 100; 之前去取值,會發生什麼事呢?

var a = 1;

(function(){
  console.log(a);    //  ?

  var a = 100;
  console.log(a);    // 100

})();

答案是,第一次的 console.log(a) 會印出 undefined,而第二次會出現 100。

因為在匿名函數獨立的 scope 內,不管 var 是放在最前面,或是最後一行,他的變數實體在該 code block 一開始就是新的了,也就是說,剛剛的 code 其實等同下面這段:

var a = 1;

(function(){
  var a;
  console.log(a);    // undefined

  a = 100;
  console.log(a);    // 100

})();

所以第一次會印出 undefined 。

要怎麼排除這樣的問題呢,很簡單,要嘛一開始就不要取相同名稱,要嘛就透過參數的方式代入原本的變數,像這樣:

var a = 1;

(function(_a){  
  console.log(_a);    // 1

  var a = 100;
  console.log(a);    // 100

})(a);

Taipei D3.js Meetup 小聚分享心得

| Comments

這次我在 Taipei D3.js Meetup (現在似乎改叫 Visual Thursday) 分享的 Talk 是有關於地理視覺化的簡介,雖然題目聽起來很學術,但其實內容是我這陣子對於 Web GIS 以及地圖視覺化的一些摸索心得分享。

感謝台灣微軟提供場地 XD

下面是我的投影片

這次幾個 Demo 的原始碼都放在 Github 上: https://github.com/kurotanshi/VisualThursday_demo
有興趣的朋友可以自行下載研究。

想看 Online Demo 的也可以直接到這: http://kurotanshi.github.io/VisualThursday_demo/

雖然都是以 Google Map 為範例,但是大部份的圖資系統如 leaflet.js / MapBox 等都是通用的,尤其是 Turf.js 這個地理資訊分析的工具,十分強大,可以直接針對 geojson 做運算,也可以透過 node 在後端執行運算。至今我還在摸索它的功能,也許未來更加熟練後可以再來分享給大家。

謝謝所有在端午連假前仍願意來參與活動的朋友,大家端午節快樂 :)

最後,我們還有很多專案想實現,歡迎有志之士加入!

[JS] [Note] TWD97 標轉換爲 經緯度

| Comments

因為從臺北市政府資料開放平台 API 拿到的資料是 TWD97 座標格式,所以我們必須要將它轉成經緯度後才能套用至 Google Map 使用。網路上查了很多資料,最後找到最親民的是米蟲大的 PHP 版本,於是就改成寫我最熟悉的 JS。

reference:
Vexed's Blog - TWD97 座標轉經緯度

function twd97_to_latlng($x, $y) {
  var pow = Math.pow, M_PI = Math.PI;
  var sin = Math.sin, cos = Math.cos, tan = Math.tan;
  var $a = 6378137.0, $b = 6356752.314245;
  var $lng0 = 121 * M_PI / 180, $k0 = 0.9999, $dx = 250000, $dy = 0;
  var $e = pow((1 - pow($b, 2) / pow($a, 2)), 0.5);

  $x -= $dx;
  $y -= $dy;

  var $M = $y / $k0;

  var $mu = $M / ($a * (1.0 - pow($e, 2) / 4.0 - 3 * pow($e, 4) / 64.0 - 5 * pow($e, 6) / 256.0));
  var $e1 = (1.0 - pow((1.0 - pow($e, 2)), 0.5)) / (1.0 + pow((1.0 - pow($e, 2)), 0.5));

  var $J1 = (3 * $e1 / 2 - 27 * pow($e1, 3) / 32.0);
  var $J2 = (21 * pow($e1, 2) / 16 - 55 * pow($e1, 4) / 32.0);
  var $J3 = (151 * pow($e1, 3) / 96.0);
  var $J4 = (1097 * pow($e1, 4) / 512.0);

  var $fp = $mu + $J1 * sin(2 * $mu) + $J2 * sin(4 * $mu) + $J3 * sin(6 * $mu) + $J4 * sin(8 * $mu);

  var $e2 = pow(($e * $a / $b), 2);
  var $C1 = pow($e2 * cos($fp), 2);
  var $T1 = pow(tan($fp), 2);
  var $R1 = $a * (1 - pow($e, 2)) / pow((1 - pow($e, 2) * pow(sin($fp), 2)), (3.0 / 2.0));
  var $N1 = $a / pow((1 - pow($e, 2) * pow(sin($fp), 2)), 0.5);

  var $D = $x / ($N1 * $k0);

  var $Q1 = $N1 * tan($fp) / $R1;
  var $Q2 = (pow($D, 2) / 2.0);
  var $Q3 = (5 + 3 * $T1 + 10 * $C1 - 4 * pow($C1, 2) - 9 * $e2) * pow($D, 4) / 24.0;
  var $Q4 = (61 + 90 * $T1 + 298 * $C1 + 45 * pow($T1, 2) - 3 * pow($C1, 2) - 252 * $e2) * pow($D, 6) / 720.0;
  var $lat = $fp - $Q1 * ($Q2 - $Q3 + $Q4);

  var $Q5 = $D;
  var $Q6 = (1 + 2 * $T1 + $C1) * pow($D, 3) / 6;
  var $Q7 = (5 - 2 * $C1 + 28 * $T1 - 3 * pow($C1, 2) + 8 * $e2 + 24 * pow($T1, 2)) * pow($D, 5) / 120.0;
  var $lng = $lng0 + ($Q5 - $Q6 + $Q7) / cos($fp);

  $lat = ($lat * 180) / M_PI;
  $lng = ($lng * 180) / M_PI;

  return {
    lat: $lat,
    lng: $lng
  };
}

在 Google Map 加入 D3 圖像 - 2

| Comments

上一篇提到了如何在 Google Map 裡面加入 D3 的圖像,這次我們實際將資料套進去吧。

資料來源是上篇提到的臺北捷運各站進出量統計的統計資料,因為台北市政府開放平台並沒有提供 CORS (跨來源資源共享)的服務,沒關係,我們直接將資料下載存成 json 檔案即可。 (範例為 2015/4 進出站人數)

按照慣例,先看結果 - Demo: http://jsbin.com/wexiva/3/
螢幕快照 2015-05-20 下午11.54.46.png

藍色的是進站人數,橘色的是出站人數。可以看出各站在 4/1 的進出站人數相當平均。

因為這次抓取的資料比較多,所以程式也稍微複雜一點,不過沒關係,概念還是很簡單的。
不囉唆直接看 code.

var map;
var overlay = new google.maps.OverlayView();
var sta_in = [], sta_out = [], mrtData;

// 讀取資料, sta_in = 2015 年四月進站人數, sta_out = 2015 年四月出站人數.

// 資料來源: http://data.taipei/opendata/datalist/datasetMeta?oid=1d71c478-205f-42c5-8386-35f86d74fdd1

d3.csv("https://dl.dropboxusercontent.com/u/12537630/mrt.csv", 
function(data){
  mrtData = data;
  
  // 進站

  d3.json("https://dl.dropboxusercontent.com/u/12537630/mrt-in-april.json", 
  function(error, json) {
    sta_in = json.result.results;
    if( sta_in.length > 0 && sta_out.length > 0 ) { drawMap(); }
  });
  
  // 出站

  d3.json("https://dl.dropboxusercontent.com/u/12537630/mrt-out-april.json", 
  function(error, json) {
    sta_out = json.result.results;
    if( sta_in.length > 0 && sta_out.length > 0 ) { drawMap(); }
  });
});

function drawMap() {

    // 設定圓餅圖長寬, 半徑

    var width = 35, height = 40, radius = Math.min(width, height) / 2;

    // 透過 d3.scale.category10() 生成顏色

    var color = d3.scale.category10();

        // d3.layout.pie()

        var pie = d3.layout.pie();
    
    // 設定圓餅內外層半徑, 這裏內層設 0.

    var arc = d3.svg.arc()
        .innerRadius(0)
        .outerRadius(radius);

    overlay.onAdd = function() {
        var layer = d3.select(this.getPanes().overlayLayer).append("div")
            .attr("class", "stations");

        overlay.draw = function() {
            var projection = this.getProjection(),
                padding = 16;
                
            // 針對每一筆捷運站增加 marker

            var marker = layer.selectAll("svg")
                .data(d3.entries(mrtData))
                .each(transform)
                .enter().append("svg")
                .each(transform)
                .attr({
                    'class': "marker",
                    "width": width,
                    "height": height,
                    "transform": "translate(" + width / 2 + "," + height / 2 + ")",
                });

            // 將取得的進出站資料透過 .data( pie([ 進站人數, 出站人數 ]) ) 指定到圓餅圖中。

            // sta_in[0] 代表 4/1 進站人數, sta_out[0] 代表 4/1 出站人數.

            var g = marker.selectAll("g")
                .data(function(d, i) {
                    return pie([parseInt(sta_in[0][d.value.name].replace(',', ''), 10), parseInt(sta_out[0][d.value.name].replace(',', ''), 10)]);
                })
                .enter()
                .append("g");

            // 著色

            g.append("path")
                .attr({
                  "fill": function(d, i) { return color(i); },
                  "d", arc,
                  "transform": "translate(" + width / 2 + "," + height / 2 + ")"
                });

            // 加入標籤

            marker.append("text")
                .attr("x", padding + 7)
                .attr("y", padding)
                .attr("dy", ".31em")
                .text(function(d) {
                    return d.value.name;
                });

            function transform(d) {
                d = new google.maps.LatLng(d.value.lat, d.value.lng);
                d = projection.fromLatLngToDivPixel(d);
                return d3.select(this)
                    .style("left", (d.x - padding) + "px")
                    .style("top", (d.y - padding) + "px");
            }
        };

    };
    overlay.setMap(map);
}

本系列文章列表:
在 Google Map 加入 D3 圖像 (1)
在 Google Map 加入 D3 圖像 (2)

在 Google Map 加入 D3 圖像

| Comments

因為昨天 台北市政府開放平台 開始提供 臺北捷運各站進出量統計 的統計資料,所以就在思考可以利用這份資料做什麼應用,第一個想到的就是能否透過 D3 與地圖的共同呈現,當然就從我最熟悉的 Google Map 開始。

不過這篇文章只會介紹到如何在 Google Map 加入 D3 (SVG) 圖像。
等我將捷運各站資訊加入後也許會還有下回,哈哈哈。

先看結果 - Demo: http://output.jsbin.com/wexiva/1/
螢幕快照 2015-05-19 下午11.34.22.png

整個程式非常簡單,首先在 Google map 加入一個 google.maps.OverlayView(),然後透過 d3.csv 載入資料。在繪製 marker (圓點) 的時候,透過自訂的 transform function 去指定它的座標就完成了。

相關程式如下:

// 捷運各站經緯度資訊: https://dl.dropboxusercontent.com/u/12537630/mrt.csv

// 資料來源: https://github.com/repeat/taipei-metro-stations

d3.csv("https://dl.dropboxusercontent.com/u/12537630/mrt.csv", function(data){
  var overlay = new google.maps.OverlayView();

  // 新增 OverlayView 到 google map

  overlay.onAdd = function() {
    var layer = d3.select(this.getPanes().overlayLayer).append("div")
        .attr("class", "stations");

    overlay.draw = function() {
      var projection = this.getProjection(), padding = 16;
      
      var marker = layer.selectAll("svg")
          .data(d3.entries(data))
          .each(transform)
          .enter().append("svg:svg")
            .each(transform)
            .attr("class", "marker");

      // 加入圓點

      marker.append("svg:circle")
          .attr("r", 6)
          .attr("cx", padding)
          .attr("cy", padding);

      // 加入標籤

      marker.append("svg:text")
          .attr("x", padding + 7)
          .attr("y", padding)
          .attr("dy", ".31em")
          .text(function(d) { return d.value.name; });

            // transform function. 指定每個點的座標.

      function transform(d) {
        d = new google.maps.LatLng(d.value.lat, d.value.lng);
        d = projection.fromLatLngToDivPixel(d);
        return d3.select(this)
            .style("left", (d.x - padding) + "px")
            .style("top", (d.y - padding) + "px");
      }
    };
  };

    // 將 overlay 加入到 google 地圖

  overlay.setMap(map);
});

參考:
http://bl.ocks.org/mbostock/899711
https://developers.google.com/maps/documentation/javascript/customoverlays?hl=zh-tw

本系列文章列表:
在 Google Map 加入 D3 圖像 (1)
在 Google Map 加入 D3 圖像 (2)

Modern WebConf 2015 與我的講題:D3 圖表優化二三事

| Comments

下面投影片是這次小弟在 Modern WebConf 2015 分享的主題,內容是有關 D3 開發的一些心得。

其實早先在準備的時候有些忐忑,像這種大拜拜的演講場合,很難預想聽眾的程度,講題太深擔心會眾無法吸收,太淺又怕對不起會眾的期待。 所以這次的內容安排了三分之一是從最基礎的 D3 data-driven 講起,再來才是開發心得與特性的介紹,期望不管是剛入門的朋友或是已經投入開發的老手都能從中獲得些什麼。因為我認為 Data-Driven 是 D3.js 的核心觀念之一,在瞭解如何將資料轉為 DOM / SVG 元件以後,剩下再去讀 D3 的 API 相信也能輕易上手。

「萬事萬物都有缺口,缺口就是光的入口」,如果有什麼是我講的不對的地方,也歡迎 用力打臉 糾正,畢竟我都這麼厚臉皮出來分享了,讓小弟我有機會獲得正確答案應該不過分,哈哈哈。

最後,在這裡預告一下,感謝 Taipei D3.js Meetup 的邀約,預計在六月份會有一場小聚的分享,題目還在構思當中。 如果你對 D3 相關議題也有興趣,歡迎與我交流。 :)

無論如何,還是感謝每一位參與 Modern WebConf 的會眾、講師以及工作人員。辛苦了。

偷偷在底下擺張 JavaScript 之父 Brendan Eich,與小弟 (自稱 JS 之子) 的合照炫耀一下 XD

IMG_8751.jpg