1. 程式人生 > >d3繪製地圖(放大顯示2 3級行政單位)

d3繪製地圖(放大顯示2 3級行政單位)

1、使用d3繪製地圖,希望隨著地圖的放大縮小顯示不同級別的行政單位,預設1級行政單位是各個省和直轄市。

實現思路:

1)改造地圖json檔案,給各個行政單位進行區域劃分

2)繪製地圖的時候預設只顯示一級行政單位。將2級及以上行政單位預設隱藏(通過class樣式)

3)地圖放大縮小(zoom函式中)時,在相應的倍數中去查詢對應的級別樣式,把display:none的樣式移除。

/**
   * @函式名稱:zoomed
   * @param dom  'g' element
   * @param transform {
   *                    x: 100,
   *                    y:100,
   *                    k:0.1,
   *                    changeCenter:boolean 是否需要改變中心點
   *                  }
   * @作用:定位並且放大縮小函式 相似功能使用函式處理
   * @date 2018/7/9
   */
  zoomed(dom, transform, changeCenter) {
    const me = this;
    // TODO 此處有個bug 拖拽原點設定有問題  需要處理
    const d = dom || d3.select('g');
    d.attr(
      'transform',
      transform
        ? 'translate(' +
          transform.x +
          ',' +
          transform.y +
          ') scale(' +
          transform.k +
          ')'
        : d3.event.transform,
    );
    // 處理字型
    const k = d3.event.transform.k;
    const tfont = TEXTFONT / k;
    d3.selectAll('.text').attr('font-size', tfont + 'px');
    // 處理線條變化
    let pathW = 1 / k;
    pathW = pathW > 1 ? 1 : pathW;
    d3.selectAll('path').attr('stroke-width', pathW);
    /**
     *  地圖是否支援分層顯示
     */
    if (LAYERED) {
      // 處理氣泡的大小
      for (let i = 0; i < 5; i++) {
        const rm = BASER / k;
        const rt = (BASER + i * 5) / k;
        i === 0 ? d3.selectAll('.bubbledata').attr('r', rm + 'px')
          : d3.selectAll('.bubbledata' + i)
            .attr('from', rm)
            .attr('to', rt);
      }
    }
    // 處理相應級別的字型顯示和隱藏  迴圈浪費資源 使用if else判斷
    setLayered();
  }
let BASER = 10; // 預設的資料圈半徑
let LAYERED = 0; // 是否支援下鑽
const TEXTFONT = 12; // 字型大小
//   修Modify改樣式集合 重複樣式不修改dom
const MODFIYSTYLE = {};
const GENERAL_LEVEL = 4;
/**
 * 對於當前 ZOOK操作的集合 只修改其中變數
 * @type {{value: number; level: number; level4: number; level3: number; level2: number; level1: number}}
 */
const ZOOMK = {
  value: 0,
  level: 0,
  level4: 6,
  level3: 3,
  level2: 2,
  level1: 1,
};
/**
 * 拿到當前的層級
 * @param key
 * @returns {number}
 */
const getlevel = function (key) {
  return key > ZOOMK.level4
    ? GENERAL_LEVEL
    : (key > ZOOMK.level3
      ? GENERAL_LEVEL - 1
      : (key > ZOOMK.level2
        ? GENERAL_LEVEL - 2
        : GENERAL_LEVEL - 3));
};

/**
 *
 * @param {string} className
 * @param {number} level  迴圈的次數
 * @param {number} changeLevel  需要改變的級別
 * @param {boolean} status  更改的狀態
 * @param {string} operator  更改的狀態  允許為 '>=' '=='
 */
const setLevelStatus = function(className: string, level: number, changeLevel: number, status: boolean, operator: string) {
  if (operator === '<=') {
    for (let i = level; i > 0; i--) {
      const itemClassName = className + i;
      i <= changeLevel
        ? setLayeredStyle(itemClassName, status)
        : setLayeredStyle(itemClassName, !status);
    }
  } else {
    for (let i = level; i > 0; i--) {
      const itemClassName = className + i;
      i === changeLevel
        ? setLayeredStyle(itemClassName, status)
        : setLayeredStyle(itemClassName, !status);
    }
  }
};
/**
 * setLayeredStyle
 * MODFIYSTYLE 利用快取機制 減少對dom的操作  提升效能
 * 使用class賦值 來優化效能
 * @param key  獲取樣式dom的值 目前是樣式
 * @param val  要設定的樣式 true為顯示 false為隱藏
 */
const setLayeredStyle = function (key, val) {
  if (MODFIYSTYLE[key] !== val) {
    d3.selectAll(key).classed('d3Chart-dom-show', val);
    MODFIYSTYLE[key] = val;
  }
};
/**
 * 處理分層 根據層次來處理各個階段是否需要分層顯示
 */
const setLayered = function () {
  const k = d3.event.transform.k;
  const Le = getlevel(k); // 獲取當前的級別
  if (k === ZOOMK.value || Le === ZOOMK.level) {
    return;
  }
  // 目前預設有4個層級 所以此處預設迴圈4次
  setLevelStatus('.citylevel', GENERAL_LEVEL, Le, true, '<=');
  ZOOMK.level = Le;
  if (LAYERED) {
    // 當前邏輯  預設分層為0 此處迴圈需要 +1
    // 獲取需要改變的層  噹噹前層次大於配置的層次 則預設配置+1層需要改變 否則就是當前層次的狀態需要改變
    const ly = LAYERED + 1;
    const changeLe = Le > ly ? ly : Le;
    setLevelStatus('.baselevel', ly, changeLe, true, '==');
  }
  ZOOMK.value = k;
};