在使用 ECharts 进行地图开发时,如果你想要圈定地图的显示范围,如:给一个坐标,绘制出周边100公里内的地图。展示出来,并在地图上绘制出范围圈。并实现范围圈跟随缩放功能,缩放范围。
项目引用
echarts 地图处理,axios 数据加载,这里就不赘述了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>一定范围内的区域地图</title>
<style>
* {
margin: 0;
padding: 0;
}
#main {
margin: 50px auto;
}
</style>
</head>
<body>
<div id="main" style="width: 1100px; height: 1100px;background-color:rgba(0, 0, 0, 0.01)"></div>
</body>
<script src="./js/axios.min.js"></script>
<script src="./js/echarts.min.js"></script>
</html>
首先获得地图数据
加载了全国,市级别geo数据。
axios
.get("https://geo.datav.aliyun.com/areas_v3/bound/100000_full_city.json")
.then((chinaJson) => {
const mGeoArr = chinaJson.data.features;
initCharts(chinaJson.data)
});
地图渲染
把geo数据渲染到屏幕显示
var myChart = echarts.init(document.getElementById("main"));
// 存储配置实例
let option = null;
// 坐标点
const mPoint = { lat: 116.418757, lon: 39.917544 };
// 地图实例
function initCharts(zhongguo) {
const markPointData = [{ name: '东城区', coord: [mPoint.lat, mPoint.lon] }];
option = {
series: [{
type: 'map',
map: 'geo',
roam: true,
zoom: 0.8,
label: {
normal: {
show: true,
textStyle: {
color: "#ccc",
},
},
emphasis: {
textStyle: {
color: "#f00",
},
},
},
markPoint: {
symbol: 'circle',
symbolSize: 240,
itemStyle: {
color: 'rgba(255,0,0,0.3)',
borderColor: '#f00'
},
data: markPointData
},
}]
};
echarts.registerMap("geo", zhongguo);
myChart.setOption(option);
}
计算两个坐标点,之间距离
function calculateDistance(point1, point2) {
const earthRadius = 6378; // 地球半径(千米)
const toRadians = (degrees) => {
return degrees * Math.PI / 180;
};
const deltaLat = toRadians(point2.lat - point1.lat);
const deltaLon = toRadians(point2.lon - point1.lon);
const a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
Math.cos(toRadians(point1.lat)) * Math.cos(toRadians(point2.lat)) *
Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = earthRadius * c;
return distance;
}
根据坐标和geo数据,计算出在范围圈内的区块
// 最大距离坐标,后面用到
let mMaxPoint = {
dis: 0,
point: []
}
function processingData(dataArr, distance) {
let mArr = [];
dataArr.forEach((ele, index) => {
const mJWDArr = ele.geometry.coordinates;
let mMaxLat = [], mMaxLon = [], mMinLat = [], mMinLon = [];
mJWDArr.forEach((item, ind) => {
item.forEach((cItem, cInd) => {
if (Array.isArray(cItem[0])) {
cItem.forEach((ccItem, ccInd) => {
if (mMaxLat.length <= 0) {
mMaxLat = ccItem;
mMaxLon = ccItem;
mMinLat = ccItem;
mMinLon = ccItem;
} else {
if (ccItem[0] > mMaxLat[0]) {
mMaxLat = ccItem;
}
if (ccItem[1] > mMaxLat[1]) {
mMaxLon = ccItem;
}
if (ccItem[0] < mMinLat[0]) {
mMinLat = ccItem;
}
if (ccItem[1] < mMinLon[1]) {
mMinLon = ccItem;
}
}
})
} else {
if (mMaxLat.length <= 0) {
mMaxLat = cItem;
mMaxLon = cItem;
mMinLat = cItem;
mMinLon = cItem;
} else {
if (cItem[0] > mMaxLat[0]) {
mMaxLat = cItem;
}
if (cItem[1] > mMaxLat[1]) {
mMaxLon = cItem;
}
if (cItem[0] < mMinLat[0]) {
mMinLat = cItem;
}
if (cItem[1] < mMinLon[1]) {
mMinLon = cItem;
}
}
}
});
});
const mCDArr = [calculateDistance(mPoint, { lat: mMaxLat[0], lon: mMaxLat[1] }), calculateDistance(mPoint, { lat: mMaxLon[0], lon: mMaxLon[1] }), calculateDistance(mPoint, { lat: mMinLat[0], lon: mMinLat[1] }), calculateDistance(mPoint, { lat: mMinLon[0], lon: mMinLon[1] })];
// 求出范围跨度最大的坐标
mCDArr.forEach((item, ind) => {
if (item > mMaxPoint.dis) {
mMaxPoint.dis = item;
if (ind === 0) {
mMaxPoint.point = mMaxLat;
} else if (ind === 1) {
mMaxPoint.point = mMaxLon;
} else if (ind === 2) {
mMaxPoint.point = mMinLat;
} else if (ind === 3) {
mMaxPoint.point = mMinLon;
}
}
});
// 设置范围内的区块
const minValue = Math.min.apply(null, mCDArr);
if (minValue <= distance) {
mArr.push(ele);
}
});
return mArr;
}
调整数据加载
……
const mGeoArr = chinaJson.data.features;
const mArrFeat = processingData(mGeoArr, 100);
initCharts({ type: "FeatureCollection", features: mArrFeat });
计算平面两点距离
function calculateDistanceCanvas(point1, point2) {
const dx = point2.x - point1.x;
const dy = point2.y - point1.y;
const distance = Math.sqrt(dx * dx + dy * dy);
return distance;
}
计算100公里在屏幕上的距离
// geo坐标转屏幕坐标
var pointInPixel = myChart.convertToPixel({
seriesIndex: 0, // 地图系列索引,通常为0
coordSys: 'series'
}, [mPoint.lat, mPoint.lon]);
var pointInPixel2 = myChart.convertToPixel({
seriesIndex: 0,
coordSys: 'series'
}, mMaxPoint.point);
// 平面两点距离
var lenPx = calculateDistanceCanvas({ x: pointInPixel[0], y: pointInPixel[1] }, { x: pointInPixel2[0], y: pointInPixel2[1] });
mLent = (lenPx / mMaxPoint.dis) * 100;
myChart.setOption({
series: [{
markPoint: {
symbolSize: mLent
}
}]
});
缩放时,markPoint画的范围不会缩放
上面用markPoint 在地图上画的范围,不会随地图缩放;所以我们要手动监听缩放实现
// 缩放范围圈功能
// 监听缩放
let mLent = 100;
myChart.on('georoam', function (event) {
mLent = mLent * event.zoom;
myChart.setOption({
series: [{
markPoint: {
symbolSize: mLent
}
}]
});
});
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="referrer" content="no-referrer" />
<title>一定范围内的区域地图</title>
<style>
* {
margin: 0;
padding: 0;
}
#main {
margin: 50px auto;
}
</style>
</head>
<body>
<div id="main" style="width: 1100px; height: 1100px;background-color:rgba(0, 0, 0, 0.01)"></div>
</body>
<script src="./js/axios.min.js"></script>
<script src="./js/echarts.min.js"></script>
<script>
function calculateDistance(point1, point2) {
const earthRadius = 6378; // 地球半径(千米)
const toRadians = (degrees) => {
return degrees * Math.PI / 180;
};
const deltaLat = toRadians(point2.lat - point1.lat);
const deltaLon = toRadians(point2.lon - point1.lon);
const a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
Math.cos(toRadians(point1.lat)) * Math.cos(toRadians(point2.lat)) *
Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = earthRadius * c;
return distance;
}
// 最大距离坐标,后面用到
let mMaxPoint = {
dis: 0,
point: []
}
function processingData(dataArr, distance) {
let mArr = [];
dataArr.forEach((ele, index) => {
const mJWDArr = ele.geometry.coordinates;
let mMaxLat = [], mMaxLon = [], mMinLat = [], mMinLon = [];
mJWDArr.forEach((item, ind) => {
item.forEach((cItem, cInd) => {
if (Array.isArray(cItem[0])) {
cItem.forEach((ccItem, ccInd) => {
if (mMaxLat.length <= 0) {
mMaxLat = ccItem;
mMaxLon = ccItem;
mMinLat = ccItem;
mMinLon = ccItem;
} else {
if (ccItem[0] > mMaxLat[0]) {
mMaxLat = ccItem;
}
if (ccItem[1] > mMaxLat[1]) {
mMaxLon = ccItem;
}
if (ccItem[0] < mMinLat[0]) {
mMinLat = ccItem;
}
if (ccItem[1] < mMinLon[1]) {
mMinLon = ccItem;
}
}
})
} else {
if (mMaxLat.length <= 0) {
mMaxLat = cItem;
mMaxLon = cItem;
mMinLat = cItem;
mMinLon = cItem;
} else {
if (cItem[0] > mMaxLat[0]) {
mMaxLat = cItem;
}
if (cItem[1] > mMaxLat[1]) {
mMaxLon = cItem;
}
if (cItem[0] < mMinLat[0]) {
mMinLat = cItem;
}
if (cItem[1] < mMinLon[1]) {
mMinLon = cItem;
}
}
}
});
});
const mCDArr = [calculateDistance(mPoint, { lat: mMaxLat[0], lon: mMaxLat[1] }), calculateDistance(mPoint, { lat: mMaxLon[0], lon: mMaxLon[1] }), calculateDistance(mPoint, { lat: mMinLat[0], lon: mMinLat[1] }), calculateDistance(mPoint, { lat: mMinLon[0], lon: mMinLon[1] })];
// 求出范围跨度最大的坐标
mCDArr.forEach((item, ind) => {
if (item > mMaxPoint.dis) {
mMaxPoint.dis = item;
if (ind === 0) {
mMaxPoint.point = mMaxLat;
} else if (ind === 1) {
mMaxPoint.point = mMaxLon;
} else if (ind === 2) {
mMaxPoint.point = mMinLat;
} else if (ind === 3) {
mMaxPoint.point = mMinLon;
}
}
});
// 设置范围内的区块
const minValue = Math.min.apply(null, mCDArr);
if (minValue <= distance) {
mArr.push(ele);
}
});
return mArr;
}
function calculateDistanceCanvas(point1, point2) {
const dx = point2.x - point1.x;
const dy = point2.y - point1.y;
const distance = Math.sqrt(dx * dx + dy * dy);
return distance;
}
</script>
<script>
// 显示坐标点,一定范围内的区域地图
var myChart = echarts.init(document.getElementById("main"));
// 存储实例
let option = null;
const mPoint = { lat: 116.418757, lon: 39.917544 };
axios
.get("https://geo.datav.aliyun.com/areas_v3/bound/100000_full_city.json")
.then((chinaJson) => {
// initCharts(chinaJson.data);
const mGeoArr = chinaJson.data.features;
const mArrFeat = processingData(mGeoArr, 100);
initCharts({ type: "FeatureCollection", features: mArrFeat });
});
// 地图实例
function initCharts(zhongguo) {
const markPointData = [{ name: '东城区', coord: [mPoint.lat, mPoint.lon] }];
option = {
series: [{
type: 'map',
map: 'geo',
roam: true,
zoom: 0.8,
label: {
normal: {
show: true,
textStyle: {
color: "#ccc",
},
},
emphasis: {
textStyle: {
color: "#f00",
},
},
},
markPoint: {
symbol: 'circle',
symbolSize: 100,
itemStyle: {
color: 'rgba(255,0,0,0.3)',
borderColor: '#f00'
},
data: markPointData
},
}]
};
echarts.registerMap("geo", zhongguo);
myChart.setOption(option);
// 缩放范围圈功能
// 监听缩放
let mLent = 100;
myChart.on('georoam', function (event) {
mLent = mLent * event.zoom;
myChart.setOption({
series: [{
markPoint: {
symbolSize: mLent
}
}]
});
});
// geo坐标转屏幕坐标
var pointInPixel = myChart.convertToPixel({
seriesIndex: 0, // 地图系列索引,通常为0
coordSys: 'series'
}, [mPoint.lat, mPoint.lon]);
var pointInPixel2 = myChart.convertToPixel({
seriesIndex: 0,
coordSys: 'series'
}, mMaxPoint.point);
// 平面两点距离
var lenPx = calculateDistanceCanvas({ x: pointInPixel[0], y: pointInPixel[1] }, { x: pointInPixel2[0], y: pointInPixel2[1] });
mLent = (lenPx / mMaxPoint.dis) * 100;
myChart.setOption({
series: [{
markPoint: {
symbolSize: mLent
}
}]
});
}
</script>
</html>