想起以前幫人作的一個地圖功能,沒有任何地理座標數據,須要生成可互動的區縣地圖html
以前echarts能夠在線生成地圖數據,可是如今由於某些緣由,echarts已經不提供這項福利了canvas
以我僅有的一點經驗,只能經過canvas讀取圖片數據生成座標數據了windows
試了一下,沒想到成功了,記錄一下整個過程api
一、首先百度,找一張須要生成區縣地圖的地圖圖片數組
二、稍作處理echarts
很是簡單的處理,用windows自帶的畫板工具就能完成,這裏就很少說了工具
三、用canvas獲取圖片數據ui
getImageData獲取到的圖片數據是一個數組,數組的內容是從坐上角第一個像素開始,從左向右,從上到下,全部像素的rgba值,因此數組的總長度應該是圖片長度乘以圖片寬度乘以4this
直接上代碼吧spa
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> html, body, canvas { padding: 0; margin: 0; display: block; } #mapimage { display: none; } </style> </head> <body> <canvas id="cvs"></canvas> <script> var mapimage, width, height var canvas = document.querySelector('#cvs') var ctx = canvas.getContext('2d') var data var imageData //getImageData得到的數據 var beginPos var inpath = [] var rgbr = 250 var rgbg = 23 var rgbb = 23 var clearr = 255 var clearg = 255 var clearb = 255 //點位順序以下圖 // 0 1 2 // 7 a 3 // 6 5 4 var checklist = [ [-1, -1], [0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], ] //主程序,將在圖片加載完成後被調用 function main() { setCanvas() setimageData() var paths = getAllPaths() drawPath(paths) addEvent(paths) } // 加載圖片 // 加載完成後調用main function loadImage(cb) { mapimage = new Image() mapimage.src = './1.jpg' mapimage.onload = function () { width = this.width height = this.height main() } } function addEvent(paths) { canvas.addEventListener('mousemove', function (e) { var path = paths[0] var x = e.offsetX var y = e.offsetY ctx.beginPath() for (var i = 0, l = path.length; i < l; i++) { ctx.lineTo(path[i][0], path[i][1]) } if (ctx.isPointInPath(x, y)) { console.log(1212) for (var i = 1, l = paths.length; i < l; i++) { path = paths[i] ctx.beginPath() for (var j = 0, lj = path.length; j < lj; j++) { ctx.lineTo(path[j][0], path[j][1]) } if (ctx.isPointInPath(x, y)) { ctx.fillStyle = 'red' } else { ctx.fillStyle = 'blue' } ctx.fill() } } }) } // 設置canvas function setCanvas() { canvas.height = mapimage.height canvas.width = mapimage.width canvas.style.height = height + 'px' canvas.style.width = width + 'px' } function checkcolor(index, r, g, b) { return data[index * 4] === r && data[index * 4 + 1] === g && data[index * 4 + 2] === b } // 處理經過canvas獲取的數據 function setimageData() { ctx.drawImage(mapimage, 0, 0) imageData = ctx.getImageData(0, 0, width, height) ctx.clearRect(0, 0, width, height) data = imageData.data // 描邊,將邊線設置爲純黑 rgba(0, 0, 0, 255) // canvas獲取的rgba數據 a通道值的範圍是0~255 for (var i = 0, l = data.length / 4; i < l; i++) { var gray = Math.floor((data[i * 4] + data[i * 4 + 1] + data[i * 4 + 2]) / 3) if (gray < 170) { data[i * 4] = 0 data[i * 4 + 1] = 0 data[i * 4 + 2] = 0 } else { if (checkcolor(i, rgbr, rgbg, rgbb)) { data[i * 4] = rgbr + 1 data[i * 4 + 1] = rgbg + 1 data[i * 4 + 2] = rgbb + 1 } } data[i * 4 + 3] = 255 } // 將邊線即純黑色像素周圍的全部點設置爲制定顏色(rgbr, rgbg, rgbb) // 路徑將經過檢測制定顏色讀取 // 因此上一次遍歷須要將制定顏色的點設爲其餘顏色 for (var i = 0, l = data.length / 4; i < l; i++) { if (checkcolor(i, 0, 0, 0)) { for (var j = 0, jl = checklist.length; j < jl; j++) { var checkp = i + checklist[j][0] + checklist[j][1] * width if (!checkcolor(checkp, 0, 0, 0)) { data[checkp * 4] = rgbr data[checkp * 4 + 1] = rgbg data[checkp * 4 + 2] = rgbb } } } } } // 遍歷全部像素 // 獲取路徑的起始點 function getBegin() { for (var i = 0, l = data.length / 4; i < l; i++) { if (data[i * 4] === rgbr && data[i * 4 + 1] === rgbg && data[i * 4 + 2] === rgbb) { return i } } } // 繪製獲取到的路徑 // 轉換座標 function drawPath(paths) { for (var j = 0, lj = paths.length; j < lj; j++) { var path = paths[j] ctx.beginPath() for (var i = 0, l = path.length; i < l; i++) { path[i] = [path[i][0] % width, Math.floor(path[i][0] / width)] ctx.lineTo(path[i][0], path[i][1]) } if (j !== 0) { ctx.fillStyle = 'blue' ctx.fill() } } } // 獲取路徑,直到全部路徑獲取完畢 function getAllPaths() { var path var paths = [] do { path = getOnePath() if (path) { paths.push(path) } } while (path) return paths } // 獲取下一個點 // 按照checklist的順序查看點周圍的8個點,以‘上一個點’的‘下一個點’爲起點,不檢查上一個點 // 沒有指定顏色的點,則返回false function getClose(index) { //這裏圖片上沒有靠近邊緣的點,因此不作邊界檢查了 if (index.length === 1) { //第一個點沒有上一個點,須要檢查全部相鄰點 //(i + 4) % 8 點相對遍歷到的點的位置 for (var i = 0, l = checklist.length; i < l; i++) { var checkp = index[0] + checklist[i][0] + checklist[i][1] * width if (checkcolor(checkp, rgbr, rgbg, rgbb)) { return [checkp, (i + 4) % 8] } } } else { //已經獲取的路徑設置成其餘顏色 //從上個點的位置開始,順時針遍歷全部點,不包括上個點 for (var i = index[1] + 1; i < index[1] + 1 + 7; i++) { var checkp = index[0] + checklist[i % 8][0] + checklist[i % 8][1] * width if (checkcolor(checkp, rgbr, rgbg, rgbb)) { return [checkp, (i + 4) % 8] } } } return false } // 獲取一條路徑 // 遍歷全部元素,遍歷到的第一個指定顏色的點做爲路徑的起始點 // 按順時針方向查看該點周圍的點是不是制定顏色 // 查看到的第一個制定顏色的點做爲下一個點 // 重複檢查,直到返回false則clear這條路徑 從新遍歷 // 或返回的下一個點與起始點相同,則這條路徑是有效的 // 將檢查過的的路徑上的點的顏色設置爲clear color // 防止重複檢查 function getOnePath() { var fail = true var begin var last var path do { try { begin = getBegin() if (begin === undefined) { return false } last = [begin] path = [last] do { last = getClose(last) if (!last) { throw new Error(1212) } path.push(last) } while (last && last[0] !== begin) fail = false } catch (e) { clearPath(path) } } while (fail) clearPath(path) return path } //清楚遍歷到的路徑 function clearPath(path) { for (var i = 0, l = path.length; i < l; i++) { var index = path[i][0] data[index * 4] = clearr data[index * 4 + 1] = clearg data[index * 4 + 2] = clearb } } loadImage() </script> </body> </html>