[原]使用node-mapnik生成openstreetmap-carto风格的瓦片
上回说到如何在CentOS上部署node-mapnik,本想着接下来学习如何使用node-mapnik生成openstreetmap的瓦片图,没想到在接下来的近40天的时间里忙成了狗!好不容易等到元旦终于有两天属于自已的时间了。经过一天时间折腾,终于可以初步实现node-mapnik生成openstreetmap-carto风格的瓦片了。
本文涉及的内容较多,而且要用到很多之前的文章中的内容,如有对其中某一个环节不明白,建议可先看前几篇文章。
现在的情况是:
1. PostgreSQL和PostGis安装好了;
2. 使用osm2pgsql将全中国的数据导入到PostGis中,库名为:gis;
(要下载全中国地图请到这里,如果是测试的话,建议不要下载过大的数据,不然导入到PostGis会非常耗时)
3. 安装了mapnik和open-mapnik;
现在的需求是:
1. 使用node-mapnik渲染地图;
2. 地图样式要和openstreetmap官方的一样;
3. 能够通过web方式获取地图瓦片;
下面详细介绍实现方法
一、配置openstreetmap官方配图样式
openstreetmap官方的样式下载是https://github.com/gravitystorm/openstreetmap-carto
建议下载百度网盘里的文件,因为官方最新(2017年1月1日)的版本有bug
链接:http://pan.baidu.com/s/1jHQwq9o 密码:vgla
下载后先进行必要的配置
1. 在导入osm数据时指定样式文件,请参考CentOS7部署osm2pgsql第六节内容。
2. 建立索引。
psql -d gis -f path/indexes.sql
3. 下载shape文件,这些文件包含世界地图,当地图级别低于9级时就不访问数据库,直接使用shape文件中数据了。
python scripts/get-shapefiles.py
不过不建议使用这个自动化工具下载,因为这些数据都在国外的服务器上,如果没有梯子就直接下,估计你一个周末就黄了,最好的方式是下载下列网盘里面的文件。
world_boundaries-spherical.tgz
链接:http://pan.baidu.com/s/1kVsK7uJ 密码:tdfc
ne_110m_admin_0_boundary_lines_land.zip
链接:http://pan.baidu.com/s/1slOwvvR 密码:z7t0
simplified-land-polygons-complete-3857.zip
链接:http://pan.baidu.com/s/1mhQYmog 密码:5tbz
land-polygons-split-3857.zip
链接:http://pan.baidu.com/s/1c2OgSYO 密码:wdpt
antarctica-icesheet-polygons-3857.zip
链接:http://pan.baidu.com/s/1nvdNvcP 密码:fzjl
antarctica-icesheet-outlines-3857.zip
链接:http://pan.baidu.com/s/1eSifwUA 密码:isdm
下载好后,在openstreetmap-carto目录中手工建一个名为 data 的文件夹,然后将这些文件放进行,一一解压,就OK了。
4. 安装Noto字体,安体下载地址是:https://noto-website-2.storage.googleapis.com/pkgs/Noto-hinted.zip
下载好后,相办法传到CentOS的 /usr/share/fonts 目录中,然后:
cd /usr/share/fonts sudo mkdir noto && cd noto sudo mv ../Noto-hinted.zip Noto-hinted.zip sudo unzip Noto-hinted.zip sudo yum install fontconfig -y fc-cache -fv sudo chmod -R 755 /usr/share/fonts sudo rm Noto-hinted.zip
这里就把基础工作做好了,现在我们仔细看看这个openstreetmap-carto目录里都有些什么
这里值得注意的是*.mss文件和project.mml文件,这些文件就是传说中的TileMill生成的样式文件,其中mml是项目文件,主要保存地图的基本属性、数据库连接、图层属性等,mss则主要是各个图层的样式。
那我们该如何使用这些样式呢?这就要稍说一下mapnik是如何工作的了。
二、配图工具及准备样式文件
mapnik提供编程的方式向一个Map对象中添加Layer对象,在这个过程中指定每个Layer的数据源以及样式
C++示例
node-mapnik示例
我们思考一下,这样好吗?很显然,如果采用这种方式,那么配置人员就需要具备编程能力,这显然不合理,那好的方法是什么呢?最好是不编程,直接写写样式文件就能配出一张图来。当然,mapnik官方也是这么想的,所以就有了XML方式了。
XML示例
这样看起来像点话了。但是做为一个和颜值有密切关系的工作,使用纯文本开发貌似也挺不合理的,在这种情况下,当...当...当,图形化的IDE就闪亮登场了。
TileMill
MapBox Studio Classic
上面我们提到的*.mss文件就是TileMill设计的样式,project.mml是TileMill的项目文件。这样就对上号了,openstreetmap-carto是TileMill设计出来的。那么这个MapBox Studio Classic又是什么呢?它和TileMill功能基本一致,也是设计CartoCSS样式文件工具。不同的是MapBox Studio Classic生成的项目文件后缀名是yml,而且生成的要素也更齐全点。但是最大的问题是MapBox Studio Classic登录帐户需要Fq!(GFW威武!)。
从网上的资料来看,MapBox Studio Classic逐渐要取代TileMill
有了所见即所得的设计器,再加上表现力丰富、看着顺眼的类CSS语法的CartoCSS,那配图工作简直So easy了!更赞的是MapBox提供了这么多的预置地图样式,是不是看着要流口水了\(^o^)/
好吧,那么现在唯一的问题是,找遍了openstreetmap-carto的文档,就是没有提如何使用!在这里就需要引入另一个工具了:Carto
安装Carto
sudo npm install -g carto --registry=https://registry.npm.taobao.org
Carto可以将mml转换为xml文件,方法如下:
carto project.mml > mapnik.xml
不过在转换之前还有一个小小的事情要做,openstreetmap-carto源码中默认的数据库连接还没有改过来,所以我们先指定PostGis的连接参数,然后再使用上面的命令生成xml样式文件,这里请注意,要先确保openstreetmap-carto目录有写入权限。
修改前:
修改后:
生成的文件如下:
三、试验生成openstreetmap-carto样式的地图
先在用户目录下生成项目文件夹,然后照着官方示例先来一发
cd ~ mkdir -p demoprojects/nodemapnik && cd demoprojects/nodemapnik vim demo1.js
输入以下内容,注意,load方法中的路径要改相应的改下啊
var mapnik = require('mapnik');
var fs = require('fs'); // register fonts and datasource plugins
mapnik.register_system_fonts();
mapnik.register_default_input_plugins(); var map = new mapnik.Map(256, 256);
map.load('/home/postgresql_data/openstreetmap-carto/mapnik.xml', function(err,map) {
if (err) throw err;
map.zoomAll();
var im = new mapnik.Image(256, 256);
map.render(im, function(err,im) {
if (err) throw err;
im.encode('png', function(err,buffer) {
if (err) throw err;
fs.writeFile('map.png',buffer, function(err) {
if (err) throw err;
console.log('saved map image to map.png');
});
});
});
});
然后运行一下
node demo1.js
生成的效果图
Good,说明一切正常没问题,接下来我们使用Web的方式生成瓦片图。
四、创建Web瓦片服务,生成指定索引的地图瓦片
1. 安装必要的nodejs模块
sudo npm install -g connect --registry=https://registry.npm.taobao.org
sudo npm install -g sphericalmercator --registry=https://registry.npm.taobao.org
2. 创建node.js应用程序(才开始接触node.js,高手轻拍)
先进入项目目录
cd ~/demoprojects/nodemapnik
创建服务器程序:app.js
var mapnik = require('mapnik')
, mercator = require('sphericalmercator')
, http = require('http')
, url = require('url')
, fs = require('fs')
, path = require('path')
, connect = require('connect'); mapnik.register_system_fonts();
mapnik.register_default_input_plugins(); var server = http.createServer(function(req, res) {
console.log('server start...'); var query = url.parse(req.url.toLowerCase(), true).query; res.writeHead(500, {
'Content-Type': 'text/plain'
}); console.log(query); if (!query || Object.keys(query).length == 0) {
console.log('open html');
try {
res.writeHead(200, {
'Content-Type': 'text/html'
});
if (req.url == '/') {
res.end(fs.readFileSync('./index.html'));
} else {
res.end(fs.readFileSync('./' + req.url));
}
} catch (err) {
res.end('Not found: ' + req.url);
}
} else { console.log('validate query'); if (query &&
query.x !== undefined &&
query.y !== undefined &&
query.z !== undefined
) { console.log('x: ' + query.x + ' y: ' + query.y + ' z: ' + query.z); var merc = new mercator({size:256});
var map = new mapnik.Map(256,256); var bbox = merc.bbox(parseInt(query.x),
parseInt(query.y),
parseInt(query.z),
false,
'900913'); console.log('begin load mapnik style'); map.loadSync('/home/postgresql_data/openstreetmap-carto/mapnik.xml'); console.log('load mapnik style success'); console.log('layers length is: ' + map.layers().length); map.zoomToBox(bbox); var img = new mapnik.Image(256,256); map.render(img, function(err, img) {
if (err) {
res.end(err.message);
} else { console.log('begin render map'); res.writeHead(200, {
'Content-Type': 'image/png'
}); console.log('x: ' + query.x + ' y: ' + query.y + ' z: '+ query.z); res.end(img.encodeSync('png')); console.log('res end');
}
});
}
}
}); console.log('start...'); connect()
.use(server)
.listen(3000);
创建前端页面:index.html
<!DOCTYPE html>
<html>
<head>
<script src="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/lib/jquery-1.10.2_d88366fd.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$('#btn').click(function(){
var x = $('#x').val();
var y = $('#y').val();
var z = $('#z').val();
$('#msg').text('x=' + x + ' y=' + y + ' z=' + z);
$('#root').empty();
$('#root').append('<img style="width:256px;height:256px" src="' + 'http://192.168.1.98:3000?x=' + x + '&y=' + y + '&z=' + z +'" alt="tile image" />');
});
});
</script>
</head>
<body>
<div><span id="msg"></span></div>
<div id="root" style="height: 256px;"> </div>
<div>
<input id="x" value="12162" style="width:50px"/>
<input id="y" value="6664" style="width:50px"/>
<input id="z" value="14" style="width:50px"/>
<input id="btn" type="button" value="get tile"/>
</div>
</body>
</html>
3. 然后在防火墙上打洞,让3000端口可以通过,或者懒点的办法,关了防火墙了事(我懒)。
systemctl stop firewalld
4. 启动服务
node app.js
5. 使用浏览器打开网页,http://服务器ip:端口号,然后点击“get tile”按钮。
初始界面
获得瓦片,完美支持万图语(图上中文左边的文字)
与openstreetmap官网对比
服务器端
至此,使用node-mapnik生成瓦片算是完工了。网上相关资料实在太少了,本文算是解决了有没有的问题,能力提升还要靠大家一起努力!如果大家在照着本文实验的时候出现问题,请留言一起讨论。
下一步的打算是:将openstreetmap-carto应用到生产环境中。架设openstreetmap生产环境的Tile Server。这涉及到node-mapnik切图、瓦片缓存、node.js单机集群等好多问题,不过github上貌似有不少现成的东西可以用,真希望我能有多点时间学习研究。
转载请注明原作者(think8848)和出处(http://think8848.cnblogs.com)
[原]使用node-mapnik生成openstreetmap-carto风格的瓦片的更多相关文章
- [原]使用node-mapnik和openstreetmap数据初步搭建瓦片服务
最近依然还是有点小忙,只能挤点时间来学习点,先解决有没有的问题,再解决好不好的问题:) 本文将承接上文<使用node-mapnik生成openstreetmap-carto风格的瓦片>的内 ...
- Go Node.js 生成的exe公布成windows服务
环境变量 GOBIN E:\01_SOFT\go1.9.2\bin GOROOT E:\01_SOFT\go1.9.2 GOPATH(下载包的存放位置:go get github.com/gin-go ...
- [原]在GeoServer中为OpenStreetMap数据设置OSM样式
转载请注明作者think8848和出处(http://think8848.cnblogs.com) 在前面几篇文章中,我们讲到了部署Postgresql,部署PostGis,部署GeoServer以及 ...
- 使用node.js生成excel报表下载(excel-export express篇)
引言:日常工作中已经有许多应用功能块使用了nodejs作为web服务器,而生成报表下载也是我们在传统应用. java中提供了2套类库实现(jxl 和POI),.NET 作为微软的亲儿子更加不用说,各种 ...
- 深度学习入门实战(一):像Prisma一样算法生成梵高风格画像
本文由云+社区发表 作者:董超 导语:现在人工智能是个大热点,而人工智能离不开机器学习,机器学习中深度学习又是比较热门的方向,本系列文章就从实战出发,介绍下如何使用MXnet进行深度学习~ 既然是实战 ...
- node.js 生成二维码
因为自己的项目中,想在商品详情页上 显示一个 商品优惠券的二维码. 以此为需求. node.js 后台代码 const qr_image = require("qr-image") ...
- 使用node自动生成html并调用cmd命令提交代码到仓库
生成html提交到git仓库 基于目前的express博客,写了一点代码,通过request模块来请求站点,将html保存到coding-pages目录,复制静态文件夹到coding-pages,最后 ...
- LSTM生成尼采风格文章
LSTM生成文本 github地址 使用循环神经网络生成序列文本数据.循环神经网络可以用来生成音乐.图像作品.语音.对话系统对话等等. 如何生成序列数据? 深度学习中最常见的方法是训练一个网络模型(R ...
- node.js生成验证码及图片
示例代码: var svgCaptcha = require('svg-captcha'); var fs = require('fs'); var codeConfig = { size: 5,// ...
随机推荐
- 【Oracle 集群】Linux下Oracle RAC集群搭建之Oracle DataBase安装(八)
Oracle 11G RAC数据库安装(八) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总 ...
- Cesium教程系列汇总
Cesium系列目录: 应用篇 入门 Cesium应用篇:1快速搭建 影像 Cesium应用篇:2影像服务(上) Cesium应用篇:2影像服务(下) 控件 Cesium应用篇:3控件(1)Clock ...
- 跨域之jsonp
我们都知道使用<script>标签可以引入外部的JS文件,即使这个JS文件来自于其他的网站,比如我们引用存放在网络服务器上的jQuery框架.在这个过程中,我们已经实现跨域访问.像< ...
- 用SignalR 2.0开发客服系统[系列5:使用SignalR的中文简体语言包和其他技术点]
前言 交流群:195866844 目录: 用SignalR 2.0开发客服系统[系列1:实现群发通讯] 用SignalR 2.0开发客服系统[系列2:实现聊天室] 用SignalR 2.0开发客服系统 ...
- 自己手写的自动完成js类
在web开发中,为了提高用户体验,会经常用到输入框的自动完成功能,不仅帮助用户进行快速输入,最重要的是帮助那些“记不全要输入什么”的用户进行选择.这个功能有很多插件已经实现了,为了适应项目的特殊需求, ...
- c++ builder 2010 错误 F1004 Internal compiler error at 0x9740d99 with base 0x9
今天遇到一个奇怪的问题,拷贝项目后,在修改,会出现F1004 Internal compiler error at 0x9740d99 with base 0x9 ,不管怎么改,删除改动,都没用,关闭 ...
- 认识Git
---恢复内容开始--- Git是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. Git作为当下最潮流的版本控制工具也是有他独特的不同,最大的不同就在于他有分布式版本管理的 ...
- kmdjs集成uglifyjs2打造极致的编程体验
回顾 上篇文章大概展示了kmdjs0.1.x时期的编程范式: 如下面所示,可以直接依赖注入到function里, kmdjs.define('main',['util.bom','app.Ball', ...
- SVG动画
动画原理 SVG动画,就是元素的属性值关于时间的变化. 如下图来说,元素的某个属性值的起始值(from)到结束值(to)在一个时间段(duration)根据时间函数(timing-function)计 ...
- 如何利用FineBI做财务分析
很多企业随着业务规模的增长,传统的财务分析方式采用手工摘取数据的方式,难以快速地对企财务经营状况作出及时分析和预测.现在业务人员通过使用自助式BI工具做财务分析已经成为流行,每个人都希望自己做报表,快 ...