概述
前面有文章基于Martin实现MapboxGL自定义底图分享了Martin的使用,本文使用网络收集的数据实现了全国基础数据的收集和基础底图。
实现后效果
实现
1. 数据准备
实例中包含如下数据:
- 边界线和九段线数据
- 省边界面数据
- 省会城市点数据
- 市边界面数据
- 市中心点数据
- 区边界面数据
- 区中心点数据
- 建筑物数据
- 河流(1级、2级和5级)
- 铁路数据
- 公路数据
- 机场数据
2. 数据入库
将准备好的数据导入的数据库中。
- 可借助QGIS实现,操作步骤可参考教程QGIS工具箱导入。
- 或借助工具
PostGIS PostGIS Bundle 3 for PostgreSQL x64 12 Shapefile and DBF Loader Exporter
导入到数据库中。可参考教程数据的导入 - 或下载我分享的数据库备份文件还原
3. 修改配置文件
在martin.exe
同级目录下新建文件config.yaml
,内容如下:
# Connection keep alive timeout [default: 75]
keep_alive: 75
# The socket address to bind [default: 0.0.0.0:3000]
listen_addresses: '0.0.0.0:3000'
# Set TileJSON URL path prefix. This overides the default of respecting the X-Rewrite-URL header.
# Only modifies the JSON (TileJSON) returned, martins' API-URLs remain unchanged. If you need to rewrite URLs, please use a reverse proxy.
# Must begin with a `/`.
# Examples: `/`, `/tiles`
base_path: /tiles
# Number of web server workers
worker_processes: 16
# Amount of memory (in MB) to use for caching tiles [default: 512, 0 to disable]
cache_size_mb: 50000
# If the client accepts multiple compression formats, and the tile source is not pre-compressed, which compression should be used. `gzip` is faster, but `brotli` is smaller, and may be faster with caching. Default could be different depending on Martin version.
preferred_encoding: gzip
# Enable or disable Martin web UI. At the moment, only allows `enable-for-all` which enables the web UI for all connections. This may be undesirable in a production environment. [default: disable]
web_ui: enable
# Database configuration. This can also be a list of PG configs.
postgres:
# Database connection string. You can use env vars too, for example:
# $DATABASE_URL
# ${DATABASE_URL:-postgresql://postgres@localhost/db} 'postgres://<database_username>:<database_userpassword>@<hostaddress>:<port_no>/<database_name>'
connection_string: 'postgresql://postgres:root@localhost:5432/lzugis'
# If a spatial table has SRID 0, then this SRID will be used as a fallback
default_srid: 4326
# Maximum Postgres connections pool size [default: 20]
pool_size: 20
# Limit the number of table geo features included in a tile. Unlimited by default.
# max_feature_count: 1000
# Control the automatic generation of bounds for spatial tables [default: quick]
# 'calc' - compute table geometry bounds on startup.
# 'quick' - same as 'calc', but the calculation will be aborted if it takes more than 5 seconds.
# 'skip' - do not compute table geometry bounds on startup.
auto_bounds: skip
# Enable automatic discovery of tables and functions.
# You may set this to `false` to disable.
auto_publish:
# Optionally limit to just these schemas
from_schemas:
- public
# Here we enable both tables and functions auto discovery.
# You can also enable just one of them by not mentioning the other,
# or setting it to false. Setting one to true disables the other one as well.
# E.g. `tables: false` enables just the functions auto-discovery.
tables:
# Optionally set how source ID should be generated based on the table's name, schema, and geometry column
source_id_format: '{table}'
# Add more schemas to the ones listed above
# A table column to use as the feature ID
# If a table has no column with this name, `id_column` will not be set for that table.
# If a list of strings is given, the first found column will be treated as a feature ID.
id_columns: gid
# Boolean to control if geometries should be clipped or encoded as is, optional, default to true
clip_geom: true
# Buffer distance in tile coordinate space to optionally clip geometries, optional, default to 64
buffer: 64
# Tile extent in tile coordinate space, optional, default to 4096
extent: 4096
functions:
# Optionally set how source ID should be generated based on the function's name and schema
source_id_format: '{schema}.{function}'
# Associative arrays of table sources
tables:
table_source_id:
# ID of the MVT layer (optional, defaults to table name)
layer_id: my_base
# Table schema (required)
schema: public
# Table name (required)
table: province,capital,city
# Geometry SRID (required)
srid: 4326
# Geometry column name (required)
geometry_column: geom
# Feature id column name
id_column: ~
# An integer specifying the minimum zoom level
minzoom: 0
# An integer specifying the maximum zoom level. MUST be >= minzoom
maxzoom: 10
# The maximum extent of available map tiles. Bounds MUST define an area
# covered by all zoom levels. The bounds are represented in WGS:84
# latitude and longitude values, in the order left, bottom, right, top.
# Values may be integers or floating point numbers.
bounds: [ -180.0, -90.0, 180.0, 90.0 ]
# Tile extent in tile coordinate space
extent: 4096
# Buffer distance in tile coordinate space to optionally clip geometries
buffer: 64
# Boolean to control if geometries should be clipped or encoded as is
clip_geom: true
# Geometry type
geometry_type: GEOMETRY
# List of columns, that should be encoded as tile properties (required)
properties:
gid: int4
# Associative arrays of function sources
functions:
function_source_id:
# Schema name (required)
schema: public
# Function name (required)
function: function_zxy_query
# An integer specifying the minimum zoom level
minzoom: 0
# An integer specifying the maximum zoom level. MUST be >= minzoom
maxzoom: 30
# The maximum extent of available map tiles. Bounds MUST define an area
# covered by all zoom levels. The bounds are represented in WGS:84
# latitude and longitude values, in the order left, bottom, right, top.
# Values may be integers or floating point numbers.
bounds: [ -180.0, -90.0, 180.0, 90.0 ]
sprites:
paths:
# all SVG files in this dir will be published as a "my_images" sprite source
# - ./icons
sources:
# SVG images in this directory will be published as a "my_sprites" sprite source
icons: ./icons
mbtiles:
paths:
# scan this whole dir, matching all *.mbtiles files
# - /dir-path
# specific mbtiles file will be published as mbtiles2 source
- ./world_cities.mbtiles
sources:
# named source matching source name to a single file
# mb-src1: /path/to/mbtiles1.mbtiles
# Font configuration
fonts:
# A list of *.otf, *.ttf, and *.ttc font files and dirs to search recursively.
- ./font/msyh.ttf
5. 启动服务
在cmd
命令窗口中输入命令.\martin.exe --config ./config.yaml
启动。
6. 前端调用
前端调用服务的完整代码如下:
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link href="./public/lib/mapbox-gl.css" rel="stylesheet" />
<style>
html,
body,
#map {
width: 100%;
height: 100%;
inset: 0;
overflow: hidden;
background-color: #efefef;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<script src="./public/lib/mapbox-gl.js"></script>
<script>
const url = 'http://localhost:3000/catalog'
fetch(url).then(res => res.json()).then(res => {
const { tiles, fonts } = res
let sources = {}, fontsArray = Object.keys(fonts)
Object.keys(tiles).forEach(tile => {
sources[tile] = {
type: "vector",
tiles: [`http://127.0.0.1:3000/${tile}/{z}/{x}/{y}`],
}
})
var style = {
version: 8,
name: "Mapbox Streets",
sprite: "http://127.0.0.1:3000/sprite/icons",
glyphs: `http://127.0.0.1:3000/font/${fontsArray.join(',')}/{fontstack}/{range}.pbf`,
sources: sources,
layers: [
// 背景图层
{
id: 'background',
type: 'background',
paint: {
'background-color': '#fff'
}
},
// 省填充
{
id: "base_province_fill",
type: "fill",
source: "base_province",
"source-layer": "base_province",
paint: {
"fill-color": "#f7f7f7",
"fill-opacity": 0.8,
},
},
// 建筑物填充
{
id: "theme_building",
type: "fill",
source: "theme_building",
"source-layer": "theme_building",
minzoom: 13,
maxzoom: 14.4,
paint: {
"fill-color": "#eeeeee",
"fill-opacity": 1,
},
},
// 建筑物拉伸
{
id: "theme_building_extrusion",
type: "fill-extrusion",
source: "theme_building",
"source-layer": "theme_building",
minzoom: 13,
paint: {
"fill-extrusion-color": "#eeeeee",
"fill-extrusion-opacity": 0.6,
'fill-extrusion-height': 25
},
},
// 建筑物描边
{
id: "theme_building_border",
type: "line",
source: "theme_building",
"source-layer": "theme_building",
minzoom: 13,
maxzoom: 14.5,
paint: {
"line-color": "#eee",
"line-opacity": 1,
},
},
// 建筑物标注
{
"id": "theme_building_label",
"type": "symbol",
"source": "theme_building",
'source-layer': 'theme_building',
minzoom: 14.5,
'layout': {
'text-field': ['get', 'name'],
'text-size': 12,
'text-allow-overlap': false,
'text-justify': 'center',
"text-font": [
"Microsoft YaHei"
]
},
paint: {
'text-color': '#a3a3a3',
'text-halo-color': '#fff',
'text-halo-width': 1.2,
}
},
// 省边界
{
id: "base_province",
type: "line",
source: "base_province",
"source-layer": "base_province",
paint: {
"line-color": "#989ea7",
"line-width": 0.5,
'line-opacity': 1,
},
},
// 城市边界
{
id: "base_city",
type: "line",
source: "base_city",
"source-layer": "base_city",
minzoom: 6,
paint: {
"line-color": "#b6ccd8",
"line-width": 0.5,
'line-opacity': 0.75,
},
},
// 区县边界
{
id: "base_county",
type: "line",
source: "base_county",
"source-layer": "base_county",
minzoom: 8.2,
paint: {
"line-color": "#b6ccd8",
"line-width": 0.3,
'line-opacity': 0.8,
},
},
// 一级水域面
{
id: "theme_hyd1_p",
type: "fill",
source: "theme_hyd1_p",
"source-layer": "theme_hyd1_p",
minzoom: 6,
paint: {
"fill-color": "#b2cefe",
"fill-opacity": 1,
},
},
// 二级水域面
{
id: "theme_hyd2_p",
type: "fill",
source: "theme_hyd2_p",
"source-layer": "theme_hyd2_p",
minzoom: 6,
paint: {
"fill-color": "#b2cefe",
"fill-opacity": 1,
},
},
// 一级水域线
{
id: "theme_hyd1_l",
type: "line",
source: "theme_hyd1_l",
"source-layer": "theme_hyd1_l",
paint: {
"line-color": "#b2cefe",
"line-width": 1,
},
},
// 5级水域线
{
id: "theme_hyd5_l",
type: "line",
source: "theme_hyd5_l",
"source-layer": "theme_hyd5_l",
minzoom: 8.4,
paint: {
"line-color": "#b2cefe",
"line-width": 0.8,
},
},
// 路网
{
id: "theme_road",
type: "line",
source: "theme_road",
"source-layer": "theme_road",
minzoom: 6,
paint: {
"line-color": "#ffac4d",
"line-width": 1,
},
},
// 铁路
{
id: "theme_railway",
type: "line",
source: "theme_railway",
"source-layer": "theme_railway",
minzoom: 8.4,
paint: {
"line-color": "#bec4cd",
"line-width": 2,
},
},
// 铁路白色
{
id: "theme_railway_bg",
type: "line",
source: "theme_railway",
"source-layer": "theme_railway",
minzoom: 8.4,
paint: {
"line-color": "#fff",
"line-width": 1.5,
},
},
// 铁路间隔
{
id: "theme_railway_interval",
type: "line",
source: "theme_railway",
"source-layer": "theme_railway",
minzoom: 8.4,
paint: {
"line-color": "#bec4cd",
"line-width": 1.5,
"line-dasharray": [3, 3]
},
},
// 国界线虚线
{
id: "base_boundry",
type: "line",
source: "base_boundry_l",
"source-layer": "base_boundry_l",
filter: ["==", "type", 1],
paint: {
"line-color": "#e04747",
"line-width": 2,
"line-dasharray": [3, 3]
},
},
// 国界线
{
id: "base_boundry_l",
type: "line",
source: "base_boundry_l",
"source-layer": "base_boundry_l",
filter: ["!=", "type", 1],
paint: {
"line-color": "#e04747",
"line-width": 2,
},
},
// 九段线
{
id: "base_nineline",
type: "line",
source: "base_nineline",
"source-layer": "base_nineline",
paint: {
"line-color": "#e04747",
"line-width": 3,
},
},
// 机场
{
"id": "theme_airport",
"type": "symbol",
"source": "theme_airport",
'source-layer': 'theme_airport',
minzoom: 8.2,
'layout': {
'icon-image': 'airport',
'icon-size': 0.55,
'icon-allow-overlap': true,
},
paint: {
'icon-color': '#f00',
}
},
// 区县名称
{
"id": "base_county_c",
"type": "symbol",
"source": "base_county_c",
'source-layer': 'base_county_c',
minzoom: 8.2,
filter: ['!=', ['get', 'district'], '北京'],
'layout': {
'icon-image': 'capital',
'icon-size': 0.32,
'icon-allow-overlap': false,
'text-field': ['get', 'district'],
'text-size': 10,
'text-allow-overlap': false,
'text-justify': 'center',
'text-offset': [0, 1.3],
"text-font": [
"Microsoft YaHei"
]
},
paint: {
'text-color': 'rgb(80, 80, 80)',
'text-halo-color': '#fff',
'text-halo-width': 1.4,
}
},
// 城市名称
{
"id": "base_city_c",
"type": "symbol",
"source": "base_city_c",
'source-layer': 'base_city_c',
minzoom: 6,
filter: ['!=', ['get', 'district'], '北京'],
'layout': {
'icon-image': 'capital',
'icon-size': 0.35,
'icon-allow-overlap': false,
'text-field': ['get', 'district'],
'text-size': 11,
'text-allow-overlap': false,
'text-justify': 'center',
'text-offset': [0, 1.3],
"text-font": [
"Microsoft YaHei"
]
},
paint: {
'text-color': 'rgb(80, 80, 80)',
'text-halo-color': '#fff',
'text-halo-width': 1.8,
}
},
// 省会城市
{
"id": "base_capital",
"type": "symbol",
"source": "base_capital",
'source-layer': 'base_capital',
filter: ['!=', ['get', 'name'], '北京'],
maxzoom: 5.9,
'layout': {
'icon-image': 'capital',
'icon-size': 0.38,
'icon-allow-overlap': false,
'text-field': ['get', 'name'],
'text-size': 12,
'text-allow-overlap': false,
'text-justify': 'center',
'text-offset': [0, 1.5],
"text-font": [
"Microsoft YaHei"
]
},
paint: {
'text-color': 'rgb(80, 80, 80)',
'text-halo-color': '#fff',
'text-halo-width': 1.8,
}
},
// 首都
{
"id": "base_capital_beijing",
"type": "symbol",
"source": "base_capital",
'source-layer': 'base_capital',
filter: ['==', ['get', 'name'], '北京'],
'layout': {
'icon-image': 'star',
'icon-size': 0.5,
'icon-allow-overlap': false,
'text-field': ['get', 'name'],
'text-size': 14,
'text-allow-overlap': false,
'text-justify': 'center',
'text-offset': [0, 1.6],
"text-font": [
"Microsoft YaHei"
]
},
paint: {
'text-color': 'rgb(255, 0, 0)',
'text-halo-color': '#fff',
'text-halo-width': 1.6,
'icon-color': '#f00',
}
},
],
};
var map = new mapboxgl.Map({
container: "map", // container ID
style: style,
center: [107.11040599933166, 34.26271532332011], // starting position [lng, lat]
zoom: 3,
minZoom: 3,
doubleClickZoom: false,
hash: false,
localFontFamily: true,
logoPosition: "bottom-right",
});
window.map = map
})
</script>
</body>
</html>
资源下载
相关资源上传到了CSDN,请异步到https://download.csdn.net/download/GISShiXiSheng/90417459下载。