通过地图图片生成可交互的地图

2023-11-04

想起之前帮人做的一个地图功能,没有任何地理坐标数据,需要生成可互动的区县地图

之前echarts可以在线生成地图数据,但是现在因为某些原因,echarts已经不提供这项福利了

图片描述

以我仅有的一点经验,只能通过canvas读取图片数据生成坐标数据了

试了一下,没想到成功了,记录一下整个过程

1、首先百度,找一张需要生成区县地图的地图图片

图片描述

2、稍做处理

图片描述

非常简单的处理,用windows自带的画板工具就能完成,这里就不多说了

3、用canvas获取图片数据

getImageData获取到的图片数据是一个数组,数组的内容是从坐上角第一个像素开始,从左向右,从上到下,所有像素的rgba值,所以数组的总长度应该是图片长度乘以图片宽度乘以4

直接上代码吧

<!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>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过地图图片生成可交互的地图 的相关文章

  • 将 OoXml 插入单词抛出错误:未知

    我一直在尝试通过office js将OOXML插入到word文档的正文内容中insertOoXML 方法 我什至尝试过最简单的实现 认为我在尝试替换 XML 本身中的 fieldCodes 时做了一些不正确的事情 所有结果都是这样Error
  • 如何在同一页面上使用AJAX处理多个表单

    我有一个表单 当我单击 提交 时 它就被提交了 然后该表单隐藏 操作页面的结果显示在 div 中 classname dig 它工作正常 但是当我添加另一个表单时 它停止正常工作并且所有表单同时提交 我如何更改我的代码 done click
  • 主干视图 DOM 元素已删除

    我一直在阅读有关 Backbone js 僵尸 或内存泄漏 问题的信息 基本上 当您不再需要该元素时 您必须从 DOM 中解除绑定并删除该元素 以确保所有事件也被删除 现在 我有一个包含几个容器的单页应用程序 div div div div
  • 尝试将布尔 C# 变量传递给 javascript 变量并将其设置为 true

    在我的 aspx 页面中 我将布尔变量 C 传递给需要布尔类型的 javascript 函数 但遇到了问题 但是 C 变量返回 True 而 javascript 不喜欢大写 myjavascript 如果我将 c 变量转换为字符串 那么我
  • jquery.find() 可以只选择直接子项吗?

    我应该向 jQuery find 提供什么参数来选择元素子元素而不选择其他元素 我不能用 gt 引导选择器 而用 将选择所有后代 而不仅仅是直接子代 我知道 jQuery children 但这是一个库 因此用户能够提供自己的选择器 并且我
  • Web 串行 API - 未捕获(承诺中)DOMException:无法打开串行端口/所需成员 baudRate 未定义

    下面的代码可以在我的 Xubuntu 机器上运行 但现在我在 Kubuntu 上 它不再工作了 它不会打开端口 Arduino IDE 工作正常 可以向开发板写入代码 并且我可以在 Chrome 中选择设备 Arduino Uno 但当我尝
  • 在 Vue.js 中从父组件执行子方法

    目前 我有一个 Vue js 组件 其中包含其他组件的列表 我知道使用 vue 的常见方式是将数据传递给孩子 并从孩子向父母发出事件 但是 在这种情况下 我想在子组件中的按钮出现时执行子组件中的方法 parent被点击 哪种方法最好 一种建
  • 解析“流”JSON

    我在浏览器中有一个网格 我想通过 JSON 将数据行发送到网格 但浏览器应该在接收到 JSON 时不断解析它 并在解析时将行添加到网格中 换句话说 在接收到整个 JSON 对象后 不应将行全部添加到网格中 应该在接收到行时将其添加到网格中
  • 如何重置使用 JavaScript 更改的 CSS 属性?

    我的导航按钮的宽度从 100px 增加到 150px 当鼠标悬停在 nav li hover width 150px 但是使用 javascript 我已经做到了 无论选择哪个选项 宽度都将继续为 150px 当选择每个选项时 它会使其他选
  • 我想检查 $('#td1').text() === "x" 是否?

    我想检查innerHtml是否有X或O 所以我不能再次添加任何其他东西 但它不起作用 添加检查代码后它就停止了 我在这里尝试做一个简单的XO游戏来更熟悉javascript和jquery 我也不确定是否可以用 jQuery 做到这一点
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • Meteor:应用程序无法在 0.9.1.1 版本上运行

    出现类似错误 Error TypeError undefined is not a function evaluating Template create anonymous function iron dynamic template j
  • 在 Wordpress 站点中进行 AJAX 调用时出现问题

    我在使用 Wordpress 站点功能的 AJAX 部分时遇到了一些问题 该功能接受在表单上输入的邮政编码 使用 PHP 函数来查找邮政编码是否引用特定位置并返回到该位置的永久链接 我的第一个问题是关于我构建的表单 现在我的表单操作是空白的
  • Google App Engine:修改云运行环境

    我正在尝试部署一个使用自定义 Node js 服务器的 Next js 应用程序 我想将自定义构建变量注入应用程序 next config js const NODE ENV process env NODE ENV const envTy
  • 从未用 @flow 标记的导入文件中获取类型定义

    TL DR我怎么告诉flow从未声明的导入模块导入类型定义 flow 加长版 流接缝能够从不使用流语法的文件中派生类型 请参阅示例 示例文件 flow js if Math random lt 0 5 var y hello else va
  • Grails 在 javascript 内的 GSP 站点中使用 grails var

    我有一个在 GSP 文件中的 javascript 代码中使用 grails 变量值的问题 例如 我有一个会话值session getAttribute selectedValue 我想在 javascript 代码部分使用这个值 我现在的
  • 为 illustrator 导出脚本以保存为 web jpg

    任何人都可以帮我为 illustrator CC2017 编写一个脚本 将文件以 JPG 格式导出到网络 旧版 然后保存文件并关闭 我有 700 个文件 每个文件有 2 个画板 单击 文件 gt 导出 gt 另存为 Web 旧版 然后右键文
  • 如何在类似控制台的环境中运行 JavaScript?

    我正在尝试遵循这里的示例 http eloquentjavascript net chapter2 html http eloquentjavascript net chapter2 html and print blah 在浏览器中运行时
  • 有没有办法阻止 prettier / prettier-now 将函数参数分解为新行

    当使用 prettier prettier now 在保存时进行格式化时 当一个函数包装另一个函数时 它会中断到一个新行 我想知道是否有办法阻止这种行为 例如 期望的输出 app get campgrounds id catchAsync
  • JQuery 图像上传不适用于未来的活动

    我希望我的用户可以通过帖子上传图像 因此 每个回复表单都有一个上传表单 用户可以通过单击上传按钮上传图像 然后单击提交来提交帖子 现在我的上传表单可以上传第一个回复的图像 但第二个回复的上传不起作用 我的提交过程 Ajax 在 php 提交

随机推荐

  • 微信小程序image组件的使用

    image属性说明 属性 类型 默认值 必填 说明 src string 否 图片资源地址 mode string scaleToFill 否 图片裁剪 缩放的模式 webp string false 否 默认不解析 webP 格式 只支持
  • java 生成excel下载_java生成excel并下载功能

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 HttpServletRequest request ServletActionContext getRequest projectId long Integer parseInt reques
  • 奇安信和深信服哪个好_网络安全头部公司全面比较

    管理 网络安全头部公司全面比较 秋名山藤原 2019 06 10 08 47 发布 选取的样本包括启明星辰 绿盟科技 奇安信 天融信 深信服 本人很看好的公司安恒信息还在静默期 就不写了 后面上市了再统一到一个表里面 关于下表有几点说明 基
  • 微电网优化调度(风、光、储能、柴油机)(Python代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 目录 1 概述 2 运行结果 3 参考文献 4 Python代码实现 详细文章 数据 文献来源 Python代码复现之 1 概述 电力对
  • Spring框架(四)Spring的Bean作用域和生命周期

    目录 一 作用域定义 二 同 类型多个 Bean 报错的解决办法 三 Bean的6种作用域 1 singleton 单例作用域 2 prototype 原型作用域 多例作用域 3 request 请求作用域 4 session 回话作用域
  • qsort的函数的使用。

    目录 一 qsort函数的定义 二 qsort的应用 1 比较数字大小 2 比较结构体类型 1 基于年龄排序 2 基于名字排序 三 基于冒泡函数自定义qsort函数 编辑 一 qsort函数的定义 使用qsort函数要加上头文件 inclu
  • 车载测试面试题,进军车企必看

    随着新能源汽车的普及 相关产业也会越来越多 很多车企都开始做 自动驾驶 了 例如 奔驰 宝马 奥迪 沃尔沃 比亚迪等等都已经开始启动 在未来 中国智能网联汽车产业将迎来爆发式增长 今天给大家分享一波车载测试相关面试题 准备进军车企的朋友可以
  • Redis3.0的主从、集群高可用

    1 安装Redis3 0 yum y install cpp binutils glibc glibc kernheaders glibc common glibc devel gcc make gcc c libstdc devel tc
  • 使用Nodejs搭建HTTP服务,并实现公网远程访问Redis数据库「内网穿透」

    文章目录 1 Linux centos8 安装redis数据库 2 配置redis数据库 3 内网穿透 3 1 安装cpolar内网穿透 3 2 创建隧道映射本地端口 4 配置固定TCP端口地址 4 1 保留一个固定tcp地址 4 2 配置
  • AI大模型及算力要求

    AI大模型对算力的要求非常高 需要高性能的硬件设备和分布式训练技术来支持 随着AI技术的不断发展 未来可能会出现更大 更复杂的模型 对算力的要求也将更高 今天和大家分享几个大模型及算力要求 希望对大家有所帮助 北京木奇移动技术有限公司 专业
  • markdown公式编号居右

  • .NET5零基础入门到项目实战(源码+课件),2021年最新版

    本套课程来自朝夕教育 NET5零基础入门到项目实战 源码 课件 课程由Richard老师 朝夕教育 Eleven Clay老师联合主讲 课程为2021年最新版视频课程 共60节 包含课程相关资料源码 共计4 1G 文章底部附下载地址 课程介
  • 优化算法 - Adadelta

    文章目录 Adadelta 1 Adadelta算法 2 代码实现 3 小结 Adadelta Adadelta是AdaGrad的另一种变体 主要区别在于前者减少了学习率适应坐标的数量 此外 广义上Adadelta被称为没有学习率 因为它使
  • pysot环境 win10 cuda10.1、torch

    1 安装anaconda 版本 Anaconda3 2019 07 python 3 7 3 跟踪Python版本对应找到Anaconda3对应版本 参考 anaconda python 版本对应关系 茶佬牛逼 CSDN博客 python3
  • 学生成绩管理系统mysql课程设计_数据库课程设计报告-学生成绩管理系统

    数据库课程设计报告 学生成绩管理系统 引 言 在现代 高科技的飞跃发展 计算机的大量普及 使得人们生活节奏越来越快 因此对教育行业的多元信息进行有效的管理工作 也成为教育行业中的重中之重 目前 学校工作繁杂 资料重多 虽然各类管理信息系统已
  • 导入自定义模块syntaxerror: invalid syntax_乐高机器人

    模块功能讲解 只剩下高级模块和自定义模块未做说明了 今天一起讲完 了解了模块的功能之后 需要通过实际的运用才能知道不同模块的功能差异 下期谈谈几个实际应用的案例 一 高级模块 一 文件读写 这个模块的功能在于将运行过程中产生的数据存储到EV
  • Linux系统安装部署Tomcat(超详细操作演示)

    Tomcat安装部署 Linux 简介 第一步 安装JDK环境 第二步 解压并部署Tomcat 简介 Tomcat 是由 Apache 开发的一个 Servlet 容器 实现了对 Servlet 和 JSP 的支持 并提供了作为Web服务器
  • Django User模型

    Django User模型 用户管理 自定义用户模型 Django自定义验证 引用User模型 视图开发 创建序列器 创建视图 创建路由 用户注册 注册序列化器 注册视图 注册路由 用户登录 登录序列化器 登录视图 登录路由 用户登出 登出
  • yyyy-MM-dd‘T‘HH:mm:ss - 里面的‘T‘是什么意思

    一 原因 今天在编写junit测试的时候发现有个日期一直显示解析失败 如下图 查看具体代码之后发现是日期格式的问题 日期格式是 yyyy MM dd T HH mm ss 失败提示 java text ParseException Unpa
  • 通过地图图片生成可交互的地图

    想起之前帮人做的一个地图功能 没有任何地理坐标数据 需要生成可互动的区县地图 之前echarts可以在线生成地图数据 但是现在因为某些原因 echarts已经不提供这项福利了 以我仅有的一点经验 只能通过canvas读取图片数据生成坐标数据