公司的新项目需要写这样的地图,还要能两级下钻到省,下面是我写好了的样子,我今天就是复一下盘:
如何用echarts显示地图
首先需要下载map的Json数据,我放到这里:mapJson
然后使用echarts的geo配置,或者series的type = 'map’就可以加载地图了:
import chinaMapJson from "./china.json"
echarts.registerMap('china', chinaMapJson)
var options = {
tooltip:{
show:false
},
geo: {
map: 'china',
roam:false,
label: {
emphasis: {
show: false
}
}
}
}
const el = document.getElementById("chart")
const chart = echart.init(el)
chart.setOption(options)
这样就可以显示中国地图。
第二种是series的type设置为map:
import chinaMapJson from "./china.json"
echarts.registerMap('china', chinaMapJson)
var options = {
tooltip:{
show:false
},
series: [
{
type: 'map',
map: 'china'
}
]
}
const el = document.getElementById("chart")
const chart = echart.init(el)
chart.setOption(options)
- 注意
中国地图的名字叫china
才会显示南海诸岛,别的名字不会显示
如何设置地图的纹理
itemStyle.areaColor
的配置文档中,写着:
-
提示
支持使用rgb(255,255,255),rgba(255,255,255,1),#fff等方式设置为纯色,也支持设置为渐变色和纹理填充// 纹理填充
{
image: imageDom, // 支持为 HTMLImageElement, HTMLCanvasElement,不支持路径字符串
repeat: ‘repeat’ // 是否平铺,可以是 ‘repeat-x’, ‘repeat-y’, ‘no-repeat’
}
可以使用这种方式来实现地图的纹理以及高亮状态的纹理
如何给地图设置阴影
地图阴影其实我使用了geo和series的两种地图叠加起来,第一层geo设置了阴影,第二层series的地图使用了描边。
const imageDom = document.createElement("img")
imageDom.src = "./texture.png"
const lightDom = document.createElement("img")
lightDom.src = "./light.png"
let options = {
tooltip:{
show:false
},
geo: {
map: '',
roam:false,
label: {
emphasis: {
show: false
}
},
itemStyle: {
shadowColor: '#C3F4F4',
shadowOffsetX:'-2px',
shadowOffsetY: '10px',
shadowBlur: '5px'
}
},
series: [
{
type: 'map',
map: 'china',
roam: false,
tooltip:{
show:false
},
label: {
show:false,
color:'#fff'
},
itemStyle: {
areaColor:imageDom,
borderColor: '#C3F4F4',
borderWidth:'2px'
},
emphasis: {
itemStyle: {
areaColor:lightDom
},
label:{
show:false
}
}
}
]
}
这样就可以绘制出效果来了
地图下钻实现
地图下钻其实就是,在地图的点击事件回调中,加载了另一份地图的json并注册地图,然后再setOption中更改了地图名字。
chart.on('click', (params) => {
if (params.componentSubType == 'map') {
goDown(params.name)
}
})
//用来存放当前的地图名字
let currentName = ''
//用来存放下钻的历史记录
let history = []
async function goDown(name){
//获取地图数据之后,修改地图options
const mapname = name
if (!echarts.getMap(name)) {
const newMapJson = await getMapJson(name)
echarts.registerMap(mapname, newMapJson)
}
options.geo.map = mapname
options.series[0].map = mapname
//然后重新绘制地图
history.push(currentName)
chart.setOption(this.options)
currentName = name
}
async function getMapJson(name) {
const jsonData = await import('./map/'+name+'.json')
return jsonData.default
}
地图回钻实现
刚刚在下钻时保存了名字和历史记录,所以回钻就是把历史记录中的最后一项弹出
function returnUpLevel() {
//先判断history有没有数据,能不能返回
if(history.length == 0){
return false
}
//取出要返回的那个名字
const name = history.pop()
const currentJson = echarts.getMap(mapname).geoJson
//修改地图配置重新绘制地图
options.geo.map = mapname
options.series[0].map = mapname
chart.setOption(options)
//修改当前的层级,名字
currentName = name
}
如何判定点是否在地图中
地图上我打了一些散点,但是在地图下钻后,有一些散点会显示在地图外,所以需要判断哪些点是需要显示的,哪些不要,具体方法我用的射线法,射线法的解释我写在另一篇里了:
射线法判断一个点是否在多边形内部
结合地图json的数据结构,我放一下判断点是否在当前地图中的代码:
function isPointInMaps(p, mapJson) {
const areas = mapJson.features
let flag = false
for(let i = 0;i < areas.length; i++) {
if(rayCasting(p, areas[i].geometry.coordinates[0])) {
flag = true
break
}
}
return flag
}
function rayCasting(p, poly) {
let px = p[0],
py = p[1],
flag = false
for(let i = 0, l = poly.length, j = l - 1; i < l; j = i, i++) {
let sx = poly[i][0],
sy = poly[i][1],
tx = poly[j][0],
ty = poly[j][1]
// 点与多边形顶点重合
if((sx === px && sy === py) || (tx === px && ty === py)) {
return true
}
// 点的射线和多边形的一条边重合,并且点在边上
if((sy === ty && sy === py) && ((sx > px && tx < px) || (sx < px && tx > px))) {
return true
}
// 判断线段两端点是否在射线两侧
if((sy < py && ty >= py) || (sy >= py && ty < py)) {
// 线段上与射线 Y 坐标相同的点的 X 坐标
let x = sx + (py - sy) * (tx - sx) / (ty - sy)
// 点在多边形的边上
if(x === px) {
return true
}
// 射线穿过多边形的边界
if(x > px) {
flag = !flag
}
}
}
// 射线穿过多边形边界的次数为奇数时点在多边形内
return flag ? true : false
}
如何自定义div写的tooltip框
echarts中的tooltip框其实很容易实现,但是我们UI小姐姐设计的。。我短时间内翻echarts配置翻不出来,所以用一个更绝的方法——div来写这个tooltip框,代码我后续会贴,思路是这样的:
- 写一个绝对定位的隐藏起来的div,写好样式
- echarts的散点触发 mouseover 事件的时候,更新div位置,更新其中的数据,并显示div
- echarts的散点触发 mouseout 事件的时候,隐藏d