d3繪製地圖(放大顯示2 3級行政單位)
阿新 • • 發佈:2018-11-10
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; };