d3.js制作條形時間范圍選擇器


此文章為原創文章,原文地址:https://www.cnblogs.com/eagle1098/p/12146688.html

效果如上圖所示。

本項目使用主要d3.js v4制作,可以用來選擇兩年的時間范圍,兩端按鈕切換年,在時間軸上標注可以選擇的時間范圍和關鍵時間點。時間數據可以在前端配置,也可以從后端請求。

此程序相對比較簡單,主要涉及d3的比例尺和拖動處理。

1)d3的比例尺其實就是把一個范圍的數據映射到另一個范圍的數據上

此處,我們使用線性比例尺:d3.scaleLinear()

它可以把一段連續的值域映射到另一段連續的值域,比如

1 var scale = d3.scaleLinear()
2    .domain([0, 730])
3    // startPos是時間橫條的開始x坐標,endPos是結束x坐標
4    .range([startPos, endPos]);

如果我們想知道兩年中的具體某天在時間橫條上對應點的x坐標,就可以把天數作為參數傳給scale(),返回值就是對應的x坐標。

當然,d3.js中還有很多其他比例尺,詳細信息可以查詢API文檔:https://github.com/d3/d3-scale#scaleLinear

此文章為原創文章,原文地址:https://www.cnblogs.com/eagle1098/p/12146688.html

2)我們這里的拖動主要分兩部分,首先是單獨拖動滑塊,然后是兩個滑塊一起拖動。

單獨拖動滑塊的邏輯:

a.如果兩個滑塊被同時拖動過,則移除兩個滑塊間的黃線。

b.使用class名稱來判斷拖動的是哪個滑塊。

c.計算鼠標x坐標,然后用比例尺反向求出對應的天數位置。

// xPos為x軸坐標
var index = scale().invert(xPos);

d.移動對應滑塊到鼠標位置。

var dragFun = function () {
      // 移除拖拽連線元素
      if (stickDragLine) {
        stickDragLine.remove();
        stickDragLine = null;
      }
      // 獲得被點擊元素class
      var className = d3.select(this).attr('class');
      // 計算鼠標x坐標,要減去滑塊寬度的二分之一
      var pos = d3.event.x - slipBlockWidth / 2;
      // 計算鼠標index,
      var index = getIndex(pos);
      var blockIndex;

      // 當前塊位置,可以配置默認位置,也可從后端請求
      if (className === 'slip-left') {
        blockIndex = splitBlockIndex.left;
      }
      if (className === 'slip-right') {
        blockIndex = splitBlockIndex.right;
      }
      // 滑塊只能在0到maxIndex之間滑動,即上層橫條內
      if (blockIndex >= 0 && blockIndex <= maxIndex) {
        if (className === 'slip-left') {
            // 移動左滑塊和相關背景和文字到鼠標位置
            changeLeftBlock(index);
        }
        if (className === 'slip-right') {
            // 移動左滑塊和相關背景和文字到鼠標位置
            changeRightBlock(index);
        }
}
// 滑塊拖動
var slipBlockDrag = d3.drag()
      .on('drag', dragFun);
// 滑塊元素調用拖拽方法
slipBlockLeft.call(slipBlockDrag);
slipBlockRight.call(slipBlockDrag);

兩個滑塊一起拖動則在它們中間增加1個黃色連線。最后使用時間條元素調用拖拽方法。

  // 主橫條上處理兩個滑塊一起拖動事件
    var stickDrag = d3.drag()
      .on('drag', function () {
        // 計算移動前兩個滑塊位置
        var leftEventX = scale(splitBlockIndex.left),
          rightEventX = scale(splitBlockIndex.right);
        if (d3.event.x > rightEventX || d3.event.x < leftEventX) {
          return;
        }
        // 添加拖動線條
        if (!stickDragLine) {
          stickDragLine = _stickG.append('line')
            .attr('x1', leftEventX + 2)
            .attr('y1', stickTop + stickHeight / 2)
            .attr('x2', rightEventX + 2)
            .attr('y2', stickTop + stickHeight / 2)
            .attr('stroke-width', 1)
            .attr('stroke', 'yellow');
        }
        // 移動后的x
        var leftAfterX = leftEventX + d3.event.dx,
          rightAfterX = rightEventX + d3.event.dx,
          // 移動后的index
          leftIndex = Math.floor(scale().invert(leftAfterX)),
          rightIndex = Math.floor(scale().invert(rightAfterX));
        if ((leftIndex >= 0 && rightIndex < maxIndex) &&
          (rightIndex >= 0 && leftIndex < maxIndex)) {
          // 保存移動后的index
          splitBlockIndex.left = leftIndex;
          splitBlockIndex.right = rightIndex;
          // 移動各元素
          changeLeftBlock(leftAfterX, splitBlockIndex.left);
          changeRightBlock(rightAfterX, splitBlockIndex.right);
          stickDragLine
            .attr('x1', leftAfterX + 2)
            .attr('x2', rightAfterX + 2);
        }        
      });
    _stickG.call(stickDrag);

文中代碼用來說明邏輯結構,具體功能函數實現起來很容易,所以沒有給出。

此文章為原創文章,原文地址:https://www.cnblogs.com/eagle1098/p/12146688.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM