經過地圖圖片生成可交互的地圖

想起以前幫人作的一個地圖功能,沒有任何地理座標數據,須要生成可互動的區縣地圖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>
相關文章
相關標籤/搜索