iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 28
1
AI & Data

D3.js資料視覺化的浪漫突進系列 第 28

Day28 D3js Diagram常見的兩點浪漫路徑

  • 分享至 

  • xImage
  •  

D3js Diagram常見的兩點浪漫路徑

用途

在繪製diagram圖表時,會用到的垂直水平連線,並且在特定位置折角,雖然d3提供了很多繪製Bezier的方法,可是實際上除了數據分析或特別的圖表外,我很少遇到需要Bezier的圖表。

概念

其實流程很簡單,幾個步驟而已。

  1. 繪製兩個方塊
  2. 連線兩個方塊
  3. 拖拉事件時更新線段路徑

拖拉事件

範例:

rect2 = rootLayer
    .append("rect")
    .attr("width", 100)
    .attr("height", 100)
    .attr("x", 500)
    .attr("y", 50)
    .call(
      d3
        .drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended)
    );

以上範例即是放置一個rect,並設定屬性後,使用d3.drag()綁定拖拉事件。

Callback的部分:

function dragstarted(event) {}

function dragged(event) {
  let target = d3.select(this);
  let offsetX = event.x - target.attr("x");
  let offsetY = event.y - target.attr("y");
  target
    .attr("x", event.x - offsetX + event.dx)
    .attr("y", event.y - offsetY + event.dy);
}
function dragended(event) {}

我們透過d3.select(this)取得拖拉事件並產生Selection
讀取目前點擊的位置與目標被點擊元件的位置算出offset後,更新目標被點擊元件的位置並加上位移值,為何要算出offset僅是因為不想讓拖拉事件一定都會以左上角定位。

繪製線段

最近路線版本

const genLine = (source, target) => {
  let ctx = d3.path();
  ctx.moveTo(source.x, source.y);
  ctx.lineTo(target.x, target.y);
  return ctx.toString();
};

其實就是直接將目前位置跟目標位置直接連線。

折線版本

const genLine = (source, target) => {
  let ctx = d3.path();
  let dx = Math.abs(source.x - target.x);
  let dy = Math.abs(source.y - target.y);

  // 兩點距離
  let dl = Math.sqrt( dx * dx + dy * dy );
  
  // 兩點XY距離加總
  let tl = Math.abs(dx + dy);
  
  // 中點座標
  let mp = {
    x: ((source.x + target.x) / 2),
    y: ((source.y + target.y) / 2)
  }
  
  // 如果小於150,沒必要特別繞中點
  if (tl - dl <= 150) {
    // 連線垂直即可
    ctx.moveTo(source.x, source.y);
    ctx.lineTo(source.x, target.y);
    ctx.lineTo(target.x, target.y);
  } else {
    // 先連線至中點
    ctx.moveTo(source.x, source.y);
    ctx.lineTo(mp.x, source.y);
    // 再連線至終點
    ctx.lineTo(mp.x, target.y);
    ctx.lineTo(target.x, target.y);
  }

  return ctx.toString();
};

其實以最後一部分來看,也只是先到達目標位置的Y,再到達目標位置的X,至於為何會有分先連線至中點呢?

中點折線

產生結過為:

普通折線

如果兩點直線連線以及折線長度相差未超過150,就會只採用普通折現,不會到中點。

結果為下:

結論

其實很多線圖,應該有更複雜更多的判斷,像是繞開碰撞元件,線段起始方向,等等更多常見diagram會實現的功能。

d3已經讓我們非常方便操作線段了,只要自己寫些數學公式,可能配合三角函數,可以玩出更多花樣。

Codepen範例

參考

d3-api


上一篇
Day27 D3js 動畫事件小技巧
下一篇
Day29 D3js d3-random 方便產亂數的小工具
系列文
D3.js資料視覺化的浪漫突進30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言