高德、百度地图自定义底图

2024-05-14 06:58

本文主要是介绍高德、百度地图自定义底图,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

项目中需要用到地图,百度地图加载自定义底图是通过切片的方式加载,而不像高德地图直接加载一张完整图片,这里瓦片加载的好处得到体现:不会因为底图文件过大导致页面加载失败或假死。
另一方面,由于自己私下学习过百度地图API的用法,对百度地图更为熟悉,故最终采用了百度地图而非高德地图。
百度底图API网址:
http://developer.baidu.com/map/index.php?title=jspopular
百度地图Demo网址:
http://developer.baidu.com/map/jsdemo.htm#a1_2

百度地图加载自定义底图

我个人比较习惯先总览一下API了解某技术有哪些功能,再通过研习demo体会对应功能的用法,感觉这样学习更实用,更快点。
想要加载底图,首先要申请自己的APP密钥,API中第一步有详解,这里不赘述。直接上例子。
原demo地址:http://developer.baidu.com/map/jsdemo.htm#g0_1
以下为源码:

<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta name="viewport" content="initial-scale=1.0, user-scalable=no" /><style type="text/css">body, html {width: 100%;height: 100%;margin:0;font-family:"微软雅黑";}#allmap{width:100%;height:500px;}#r-result{width:100%;margin-top:5px;}p{margin:5px; font-size:14px;}</style><script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=您的密钥"></script><title>叠加魔兽地图</title>
</head>
<body><div id="allmap"></div><div id="r-result"><input type="button" onclick="add_control();" value="添加" /><input type="button" onclick="delete_control();" value="删除" /></div>
</body>
</html>
<script type="text/javascript">// 百度地图API功能var map = new BMap.Map('allmap');map.addControl(new BMap.NavigationControl({anchor: BMAP_ANCHOR_TOP_RIGHT, type: BMAP_NAVIGATION_CONTROL_SMALL}));map.centerAndZoom(new BMap.Point(0, 0), 3);var tileLayer = new BMap.TileLayer();tileLayer.getTilesUrl = function(tileCoord, zoom) {var x = tileCoord.x;var y = tileCoord.y;var url = 'http://developer.baidu.com/map/jsdemo/demo/tiles/' + zoom + '/tile' + x + '_' + y + '.png';     //根据当前坐标,选取合适的瓦片图return url;}function add_control(){map.addTileLayer(tileLayer);}function delete_control(){map.removeTileLayer(tileLayer);}add_control();
</script>

有点js基本功的话,不难看出,地图的瓦片是通过拼接底图瓦片的文件名加载的,因此我们需要将自己的底图进行切片,并按规则命名图片。
切片暂未找到较好工具,只在网络上找到一段代码(感谢源代码作者,不过不记得在哪找到的了,这里先说声抱歉),虽然不够完善,但暂时基本够用,代码有个不足是:

1、不能切很大的图片文件;
2、切较大的图片文件切片有点慢,代码作者也说了原因是由于切片使用单线程,可以进一步优化改成多线程提高效率。

由于项目急用,暂时也还没改,我会抽空试试。
以下是我个人测试用的代码:

package com.haycm.service;import java.io.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.Graphics;
import java.awt.color.ColorSpace;
import javax.imageio.ImageIO;public class ImageCut {public static void main(String[] args) {cut("E:\\world.jpg", "E:\\", 300, 300);}/*** 图像切割** @param srcImagePath 源图像地址* @param destDir      切片目标文件夹* @param destWidth    目标切片宽度* @param destHeight   目标切片高度*/public static void cut(String srcImagePath, String destDir, int destWidth, int destHeight) {try {Image img;ImageFilter cropFilter;// 读取源图像BufferedImage bi = ImageIO.read(new File(srcImagePath));int srcWidth = bi.getHeight(); // 源图宽度int srcHeight = bi.getWidth(); // 源图高度if (srcWidth > destWidth && srcHeight > destHeight) {Image image = bi.getScaledInstance(srcWidth, srcHeight, Image.SCALE_DEFAULT);
//                destWidth = 200; // 切片宽度
//                destHeight = 200; // 切片高度int cols = 0; // 切片横向数量int rows = 0; // 切片纵向数量// 计算切片的横向和纵向数量if (srcWidth % destWidth == 0) {cols = srcWidth / destWidth;} else {cols = (int) Math.floor(srcWidth / destWidth) + 1;}if (srcHeight % destHeight == 0) {rows = srcHeight / destHeight;} else {rows = (int) Math.floor(srcHeight / destHeight) + 1;}// 循环建立切片// 改进的想法:是否可用多线程加快切割速度for (int y = 0; y < rows; y++) {for (int x = 0; x < cols; x++) {// 四个参数分别为图像起点坐标和宽高// 即: CropImageFilter(int x,int y,int width,int height)cropFilter = new CropImageFilter(x * destWidth, y * destHeight, destWidth, destHeight);img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(),cropFilter));BufferedImage tag = new BufferedImage(destWidth,destHeight, BufferedImage.TYPE_INT_RGB);Graphics g = tag.getGraphics();g.drawImage(img, 0, 0, null); // 绘制缩小后的图g.dispose();// 输出为文件if (!new File(destDir).exists())new File(destDir).mkdirs();ImageIO.write(tag, "JPEG", new File(destDir + "map_-" + (y) + "_" + (x) + ".jpg"));}}System.out.println("image cut finished ");}} catch (Exception e) {e.printStackTrace();}}/*** 缩放图像** @param srcImageFile 源图像文件地址* @param result       缩放后的图像地址* @param scale        缩放比例* @param flag         缩放选择:true 放大; false 缩小;*/public static void scale(String srcImageFile, String result, int scale,boolean flag) {try {BufferedImage src = ImageIO.read(new File(srcImageFile)); // 读入文件int width = src.getWidth(); // 得到源图宽int height = src.getHeight(); // 得到源图长if (flag) {// 放大width = width * scale;height = height * scale;} else {// 缩小width = width / scale;height = height / scale;}Image image = src.getScaledInstance(width, height,Image.SCALE_DEFAULT);BufferedImage tag = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);Graphics g = tag.getGraphics();g.drawImage(image, 0, 0, null); // 绘制缩小后的图g.dispose();ImageIO.write(tag, "JPEG", new File(result));// 输出到文件流} catch (IOException e) {e.printStackTrace();}}/*** 图像类型转换* GIF->JPG GIF->PNG PNG->JPG PNG->GIF(X)*/public static void convert(String source, String result) {try {File f = new File(source);f.canRead();f.canWrite();BufferedImage src = ImageIO.read(f);ImageIO.write(src, "JPG", new File(result));} catch (Exception e) {e.printStackTrace();}}/*** 彩色转为黑白** @param source* @param result*/public static void gray(String source, String result) {try {BufferedImage src = ImageIO.read(new File(source));ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);ColorConvertOp op = new ColorConvertOp(cs, null);src = op.filter(src, null);ImageIO.write(src, "JPEG", new File(result));} catch (IOException e) {e.printStackTrace();}}
}

这里要注意的是,要根据自己需要,定义图片文件的命名规律,否则切出来的图片名称在百度地图中加载顺序有错,不能拼接为完整图片。
(这里也可以不用关心切图文件的命名规则,只需要在百度地图中加载图片的时候修改加载图片的文件名规律其实也可以的,只是我觉得切图的时候确定命名规则更好理解一点)
先上传一张原图,在通过切图结果比较命名规律和预览效果。
以下为完整原图:
完整原图
以下为切片后文件夹预览截图:
预览截图
由此可见,只要命名规则定义好,切出来的图片和原图是没多大差别的,这时就可以用于百度地图中作为底图了。
以下为我的百度地图测试代码:

<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><meta name="viewport" content="initial-scale=1.0, user-scalable=no"/><style type="text/css">body, html {width: 100%;height: 100%;margin: 0;font-family: "微软雅黑";}#allmap {width: 100%;height: 100%;}#r-result {width: 100%;margin-top: 5px;}p {margin: 5px;font-size: 14px;}</style><script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=您的密钥"></script><title>叠加底图</title>
</head>
<body>
<div id="allmap"></div>
<div id="r-result"><input type="button" onclick="add_control();" value="添加"/><input type="button" onclick="delete_control();" value="删除"/>
</div>
</body>
</html>
<script type="text/javascript">var sValue = 1;// 百度地图API功能var map = new BMap.Map('allmap');
//        map.enableScrollWheelZoom(false);map.addControl(new BMap.NavigationControl({anchor: BMAP_ANCHOR_TOP_RIGHT, type: BMAP_NAVIGATION_CONTROL_SMALL}));map.centerAndZoom(new BMap.Point(0, 0), 8);var tileLayer = new BMap.TileLayer();tileLayer.getTilesUrl = function (tileCoord, zoom) {var x = tileCoord.x;var y = tileCoord.y;console.log("x: " + x + "---" + "y:" + y + "---->");var url = '../../image/sg/map_' + (y) + '_' + (x) + '.jpg';    //根据当前坐标,选取合适的瓦片图return url;};function add_control() {map.addTileLayer(tileLayer);}function delete_control() {map.removeTileLayer(tileLayer);}add_control();
</script>

这样就可以通过百度地图加载自定义底图了。
效果预览:
加载结果预览图
但是这样加载的底图是不能缩放的,或者说,缩放地图的时候,虽然百度地图的比例尺缩放了,但是自定义的底图并没有缩放,还是显示的原来大小,项目中暂时还没有用到缩放,具体还没研究。
我的思路是:根据不同比例进行切图,切出多份瓦片图,当加载时通过“map_比例尺+x坐标+y坐标.png”的方式来加载图片,这样一来就可以实现不同比例尺加载不同比例瓦片的效果了。

高德地图加载底图简介

高德加载底图也有利有弊,它是直接加载一张完整图片,并且可以根据比例尺缩放,省去了切图的过程,不足是当底图很大(比如我项目用到一个20MB的底图)的时候,页面会加载很慢,甚至可能假死,这肯定是我们不愿意看到的,这里我只贴以下我用高德地图的测试代码(其实可以直接参考官网demo,换一下图片地址就好,用很大的图片尝试一下)

<!DOCTYPE html>
<html><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width"><title>叠加图片图层</title><link rel="stylesheet" href="http://cache.amap.com/lbs/static/main.css"/><script src="./amap.js"></script><style>.marker {color: #ff6600;padding: 4px 10px;border: 1px solid #fff;white-space: nowrap;font-size: 12px;font-family: "";background-color: #0066ff;}</style>
</head><body>
<div id="mapContainer"></div><script>var imageLayer = new AMap.ImageLayer({url: '111.jpg',
//        url: '../../image/sanguo/world.jpg',bounds: new AMap.Bounds([116.327911, 39.939229],[116.342659, 39.946275]),zooms: [15, 18]});var map = new AMap.Map('mapContainer', {scrollWheel: true,center: [116.33910, 39.945084],zoom: 18,layers: [new AMap.TileLayer(),imageLayer]});var _onClick = function (e) {new AMap.Marker({position: e.lnglat,map: map});console.log(e.lnglat);};AMap.event.addListener(map, "click", _onClick); //绑定事件,返回监听对象</script>
</body></html>

下面是加载时间对比图:
加载时间对比
通过chrome的devTools不难看出,这种加载方式加载较大文件的底图时较慢,相比于其它的几百毫秒,大图片加载花费了1.74S的时间。
我试过多次,这还是通过本地文件方式加载的,如果是网络环境的话,可想而知一个页面加载40MB的图片需要多久,这显然不是我们想要的。
不过综合高德和百度的利弊各自选择吧。

说明

最后,记下博文TODO:
1、修改切片程序,解决切图慢的问题和大图片切片时内存不足问题;
2、继续研究百度地图的比例尺缩放

这篇关于高德、百度地图自定义底图的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/988063

相关文章

springboot项目中整合高德地图的实践

《springboot项目中整合高德地图的实践》:本文主要介绍springboot项目中整合高德地图的实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一:高德开放平台的使用二:创建数据库(我是用的是mysql)三:Springboot所需的依赖(根据你的需求再

如何自定义一个log适配器starter

《如何自定义一个log适配器starter》:本文主要介绍如何自定义一个log适配器starter的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求Starter 项目目录结构pom.XML 配置LogInitializer实现MDCInterceptor

Druid连接池实现自定义数据库密码加解密功能

《Druid连接池实现自定义数据库密码加解密功能》在现代应用开发中,数据安全是至关重要的,本文将介绍如何在​​Druid​​连接池中实现自定义的数据库密码加解密功能,有需要的小伙伴可以参考一下... 目录1. 环境准备2. 密码加密算法的选择3. 自定义 ​​DruidDataSource​​ 的密码解密3

spring-gateway filters添加自定义过滤器实现流程分析(可插拔)

《spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔)》:本文主要介绍spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔),本文通过实例图... 目录需求背景需求拆解设计流程及作用域逻辑处理代码逻辑需求背景公司要求,通过公司网络代理访问的请求需要做请

使用Python和Pyecharts创建交互式地图

《使用Python和Pyecharts创建交互式地图》在数据可视化领域,创建交互式地图是一种强大的方式,可以使受众能够以引人入胜且信息丰富的方式探索地理数据,下面我们看看如何使用Python和Pyec... 目录简介Pyecharts 简介创建上海地图代码说明运行结果总结简介在数据可视化领域,创建交互式地

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

如何自定义Nginx JSON日志格式配置

《如何自定义NginxJSON日志格式配置》Nginx作为最流行的Web服务器之一,其灵活的日志配置能力允许我们根据需求定制日志格式,本文将详细介绍如何配置Nginx以JSON格式记录访问日志,这种... 目录前言为什么选择jsON格式日志?配置步骤详解1. 安装Nginx服务2. 自定义JSON日志格式各

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

基于Spring实现自定义错误信息返回详解

《基于Spring实现自定义错误信息返回详解》这篇文章主要为大家详细介绍了如何基于Spring实现自定义错误信息返回效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录背景目标实现产出背景Spring 提供了 @RestConChina编程trollerAdvice 用来实现 HTT