Skip to content

Commit 1b77cc0

Browse files
author
doodlewind
committed
init cmap
0 parents commit 1b77cc0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+3161
-0
lines changed

CMap.vue

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
<template>
2+
<div class="cmap-container" v-bind:style="{ height: height, width: width}">
3+
<transition name="fade">
4+
<div class="cmap-btn" v-if="zoomed" @click="back">返回</div>
5+
</transition>
6+
<div class="cmap-info" v-if="hasInfo">
7+
<b>{{currentTile}}</b>: {{currentTileVal}}
8+
</div>
9+
<transition name="fade">
10+
<div class="cmap-mask" v-if="isLoading">
11+
<p>Loading…</p>
12+
</div>
13+
</transition>
14+
</div>
15+
</template>
16+
17+
<script>
18+
import 'leaflet/dist/leaflet.css'
19+
import L from 'leaflet'
20+
import loader from './modules/loader'
21+
import render from './modules/render'
22+
import initConf from './modules/conf'
23+
var conf = {}
24+
25+
export default {
26+
props: ['mapData', 'mapConf'],
27+
created() { conf = Object.assign({}, initConf, this.mapConf) },
28+
data() {
29+
return {
30+
width: '100%',
31+
height: '550px',
32+
zoomed: false,
33+
isLoading: false,
34+
currentTile: null,
35+
currentProvince: null,
36+
currentTileVal: '-',
37+
hasInfo: false
38+
}
39+
},
40+
methods: {
41+
back() {
42+
render.backToCountry(this, conf, this.map)
43+
this.zoomed = false
44+
this.currentTile = ''
45+
this.hasInfo = false
46+
},
47+
showInfo(type, name) {
48+
var area
49+
if (type == 'country') {
50+
area = this.mapData.find(p => p.name == name)
51+
}
52+
else {
53+
area = (() => {
54+
var province = this.mapData.find(p => p.name == this.currentProvince)
55+
return province ? province.children.find(c => c.name == name) : null
56+
})()
57+
}
58+
this.hasInfo = true
59+
this.currentTile = name
60+
this.currentTileVal = area ? area.value : '-'
61+
},
62+
hideInfo() {
63+
this.hasInfo = false
64+
this.currentTile = ''
65+
this.currentTileVal = '-'
66+
}
67+
},
68+
mounted() {
69+
if (!conf.scale) {
70+
conf.scale = loader.getColorScale(conf.colors, this.mapData)
71+
}
72+
73+
var vm = this
74+
var map = L.map(this.$el, {
75+
attributionControl: false,
76+
zoomControl: conf.hasZoomControl,
77+
maxBounds: conf.countryBounds,
78+
minZoom: 3
79+
}).fitBounds(conf.countryBounds)
80+
81+
if (conf.hasTileLayer) {
82+
L.tileLayer('//{s}.tile.osm.org/{z}/{x}/{y}.png', {
83+
// TODO
84+
}).addTo(map)
85+
}
86+
87+
// 初始化国家地图
88+
vm.isLoading = true
89+
loader.load('china', data => {
90+
var country = L.geoJson(data, {
91+
style: feature => render.provinceStyle(feature, conf, this.mapData),
92+
onEachFeature: (feature, layer) => {
93+
layer.on({
94+
mouseover: e => render.highlightFeature(vm, 'country', conf.highlightStyle, e),
95+
mouseout: e => render.resetHighlight(vm, country, e),
96+
// 仅需在初始加载时判断是否需要城市视图
97+
click: conf.hasCityView ? e => render.zoomIn(vm, conf, country, map, e) : () => {}
98+
})
99+
}
100+
}).addTo(map);
101+
vm.isLoading = false
102+
})
103+
104+
vm.map = map
105+
}
106+
}
107+
</script>
108+
109+
<style scoped>
110+
.cmap-container {
111+
position: relative;
112+
margin: 0 auto;
113+
}
114+
.cmap-info, .cmap-btn {
115+
position: absolute;
116+
height: 25px;
117+
padding: 5px 15px;
118+
font: 14px Arial, Helvetica, sans-serif;
119+
line-height: 25px;
120+
vertical-align: middle;
121+
border-radius: 4px;
122+
box-shadow: 0 2px 3px grey;
123+
color: black;
124+
background: white;
125+
z-index: 999;
126+
cursor: pointer;
127+
}
128+
.cmap-btn {
129+
bottom: 15px;
130+
left: 10px;
131+
}
132+
.cmap-info {
133+
bottom: 15px;
134+
right: 10px;
135+
}
136+
.cmap-mask {
137+
position: absolute;
138+
width: 100%;
139+
height: 100%;
140+
display: flex;
141+
justify-content: space-around;
142+
align-items: center;
143+
background-color: rgba(100, 100, 100, .4);
144+
z-index: 1000;
145+
}
146+
.cmap-mask > p {
147+
display: block;
148+
text-align: center;
149+
color: white;
150+
font: 20px Arial, Helvetica, sans-serif;
151+
}
152+
153+
.leaflet-container {
154+
background: transparent !important;
155+
}
156+
157+
.fade-enter-active, .fade-leave-active {
158+
transition: opacity .4s ease;
159+
}
160+
.fade-enter, .fade-leave-active {
161+
opacity: 0
162+
}
163+
</style>

README-cn.md

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# vue-cmap
2+
Vue 中国地图可视化组件,支持 Drilldown 切换国家 / 省份视图
3+
4+
![vue-cmap-country](http://7u2gqx.com1.z0.glb.clouddn.com/vue-cmap-1.png)
5+
6+
![vue-cmap-province](http://7u2gqx.com1.z0.glb.clouddn.com/vue-cmap-2.png)
7+
8+
9+
## 特性
10+
* 平滑的省市视图切换
11+
* 可叠加 OpenStreetMap 贴片地图
12+
* 惰性加载地形数据(基于 Code Splitting,无需配置后端接口)
13+
* 参数化的定制样式
14+
* 极轻,初始数据量小于 80K
15+
16+
Clone this repo and run example:
17+
18+
``` text
19+
cd vue-cmap/example
20+
npm run dev
21+
```
22+
23+
24+
## Demo
25+
Clone 本仓库并执行构建:
26+
27+
``` text
28+
cd vue-cmap/example
29+
npm run dev
30+
```
31+
32+
33+
## 导入
34+
按标准 Vue 组件导入方式导入即可:
35+
36+
``` text
37+
npm install vue-cmap
38+
```
39+
40+
``` html
41+
<template>
42+
<c-map :mapData="myMapData"></c-map>
43+
</template>
44+
45+
<script>
46+
import CMap from 'vue-cmap'
47+
48+
export default {
49+
data() {
50+
return {
51+
myMapData: [
52+
{ name: "安徽", value: 200, children: [] }
53+
]
54+
}
55+
},
56+
components: { CMap }
57+
}
58+
</script>
59+
```
60+
61+
62+
## API
63+
CMap 组件的数据和配置均以 Vue 的标准 `props` 形式传入,若地图数据在初始化 CMap 后保持不变,可在引入组件时添加 `v-once` 指令以优化性能:
64+
65+
``` html
66+
<c-map
67+
v-once
68+
:mapData="myMapData"
69+
:mapConf="myMapConf">
70+
</c-map>
71+
```
72+
73+
### mapData
74+
通过该 `props` 传入省市数据。由于全国城市数量固定,故在此可将省份和城市数据全量传入,传入省市数据的顺序、数量均不限(缺少数据的省市会显示为灰色)。数据格式如下:
75+
76+
``` js
77+
const myMapData = [
78+
{
79+
// name 需与省份中文名保持一致
80+
name: "安徽",
81+
value: 200,
82+
children: [
83+
{ name: "黄山市", value: 100 },
84+
{ name: "合肥市", value: 100 }
85+
// ...
86+
]
87+
},
88+
{ name: '北京', value: 300, children: [] }
89+
// ...
90+
]
91+
```
92+
93+
### mapConf
94+
通过该 `props` 传入 CMap 配置参数信息。传入的参数将与如下的默认参数合并后,再用于渲染图表:
95+
96+
``` js
97+
export default {
98+
colors: ['#800026', '#BD0026', '#E31A1C', '#FC4E2A', '#FD8D3C', '#FEB24C', '#FED976', '#FFEDA0'],
99+
scale: null,
100+
width: '100%',
101+
height: '550px',
102+
hasCityView: true,
103+
hasTileLayer: false,
104+
hasZoomControl: true,
105+
countryBounds: [[18, 72], [54, 137]],
106+
tileStyle: {
107+
weight: 2,
108+
opacity: 1,
109+
borderColor: 'white',
110+
dashArray: 4,
111+
fillOpacity: 0.7
112+
},
113+
highlightStyle: {
114+
weight: 5,
115+
borderColor: '#666',
116+
dashArray: 0,
117+
fillOpacity: 0.7
118+
}
119+
}
120+
```
121+
122+
#### width
123+
Type: `String` Default: `100%`
124+
125+
地图区域宽度。
126+
127+
#### height
128+
Type: `String` Default: `550px`
129+
130+
地图区域高度。
131+
132+
#### colors
133+
Type: `Array`
134+
135+
地图配色数组,数量不限。数组中越靠后的颜色用于渲染越大的数据。数据将按大小顺序均匀分配各颜色。
136+
137+
#### scale
138+
Type: `Object` Default: `null`
139+
140+
需要手动定义地图各颜色阈值时,传入该参数。该参数存在时,`colors` 不生效。格式如下:
141+
142+
``` js
143+
const scale = [
144+
{ color: 'green', threshold: 100 }, // 小于等于 100 的数据为绿色
145+
{ color: 'yellow', threshold: 200 }, // 小于等于 200 的数据为黄色
146+
{ color: 'red', threshold: 300 }, // 小于等于 300 的数据为红色
147+
]
148+
```
149+
150+
在默认情况下 `scale` 由 CMap 组件根据传入数据自动生成,无需手动定义颜色与数据的对应关系。
151+
152+
#### hasCityView
153+
Type: `Boolean` Default: `true`
154+
155+
是否展示各省下的城市详细数据。
156+
157+
#### hasTileLayer
158+
Type: `Boolean` Default: `false`
159+
160+
是否加载来自 Open Street Map 的贴片地图。
161+
162+
#### hasZoomControl
163+
Type: `Boolean` Default: `true`
164+
165+
是否显示地图缩放控件。
166+
167+
#### countryBounds
168+
Type: `Array` Default: `[[18, 72], [54, 137]]`
169+
170+
初始化时加载的中国经纬度,地图的缩放和平移均限制在该范围内。
171+
172+
#### tileStyle
173+
Type: `Object`
174+
175+
地图省市 Tile 样式,默认参数如下:
176+
177+
``` js
178+
const tileStyle = {
179+
weight: 2, // 边框宽度
180+
opacity: 1, // 内容透明度
181+
borderColor: 'white', // 边框颜色
182+
dashArray: 4, // 边框间隔长度
183+
fillOpacity: 0.7 // 边框透明度
184+
}
185+
```
186+
187+
#### highlightStyle
188+
Type: `Object`
189+
190+
Hover 时的 Tile 样式,默认参数如下:
191+
192+
``` js
193+
const tileStyle = {
194+
weight: 5, // 边框宽度
195+
borderColor: '#666', // 边框颜色
196+
dashArray: 0, // 边框间隔长度
197+
fillOpacity: 0.7 // 边框透明度
198+
}
199+
```

0 commit comments

Comments
 (0)