背景
近期工作中涉及大量百度mapv使用。其中包含,汇聚图效果、动态街道路径效果、动态热力图效果。
百度mapv引入
<script src="http://mapv.baidu.com/build/mapv.min.js"></script>
热力图
/**
* 绘制热力图
*/
drowHotDary() {
var randomCount = 600;
var data = []; // 清除所有遮盖物
this.clearCurrentBoundCity()
// 构造数据
while (randomCount--) {
var cityCenter = mapv.utilCityCenter.getCenterByCityName(this.hotMapcitys[parseInt(Math.random() * this.hotMapcitys.length)]);
data.push({
geometry: {
type: 'Point',
coordinates: [cityCenter.lng - 2 + Math.random() * 2, cityCenter.lat - 2 + Math.random() * 2]
},
count: 30 * Math.random(),
time: 100 * Math.random()
});
}
var dataSet = new mapv.DataSet(data);
var options = {
size: 13,
gradient: { 0.25: "rgb(0,0,255)", 0.55: "rgb(0,255,0)", 0.85: "yellow", 1.0: "rgb(255,0,0)"},
max: 60,
animation: {
type: 'time',
stepsRange: {
start: 0,
end: 100
},
trails: 10,
duration: 10,
},
draw: 'heatmap'
}
var mapvLayer = new mapv.baiduMapLayer(this.map, dataSet, options);
},
汇聚图效果
/**
* 汇聚图
*/
drawConvergenceMap() {
var randomCount = 100;
var node_data = {
"0":{"x":116.4136103013, "y":39.9110666857},
"1":{"x":121.485124, "y":31.235317},
};
var edge_data = [
{"source":"1", "target":"0"}
]
var citys = ["承德", "莆田", "宜昌","重庆"];
// 构造数据
for (var i = 1; i < randomCount; i++) {
var cityCenter = mapv.utilCityCenter.getCenterByCityName(citys[parseInt(Math.random() * citys.length)]);
node_data[i] = {
x: cityCenter.lng - 5 + Math.random() * 10,
y: cityCenter.lat - 5 + Math.random() * 10,
}
edge_data.push(
{"source": ~~(i * Math.random()), "target": '0'}
);
}
var fbundling = mapv.utilForceEdgeBundling()
.nodes(node_data)
.edges(edge_data);
var results = fbundling();
var data = [];
var timeData = [];
for (var i = 0; i < results.length; i++) {
var line = results[i];
var coordinates = [];
for (var j = 0; j < line.length; j++) {
coordinates.push([line[j].x, line[j].y]);
timeData.push({
geometry: {
type: 'Point',
coordinates: [line[j].x, line[j].y]
},
count: 1,
time: j
});
}
data.push({
geometry: {
type: 'LineString',
coordinates: coordinates
}
});
}
var dataSet = new mapv.DataSet(data);
var options = {
strokeStyle: 'rgba(55, 50, 250, 0.3)',
globalCompositeOperation: 'lighter',
shadowColor: 'rgba(55, 50, 250, 0.5)',
shadowBlur: 10,
methods: {
click: function (item) {
}
},
lineWidth: 1.0,
draw: 'simple'
}
var mapvLayer = new mapv.baiduMapLayer(this.map, dataSet, options);
var dataSet = new mapv.DataSet(timeData);
var options = {
fillStyle: 'rgba(255, 250, 250, 0.9)',
globalCompositeOperation: 'lighter',
size: 1.5,
animation: {
type: 'time',
stepsRange: {
start: 0,
end: 100
},
trails: 1,
duration: 5,
},
draw: 'simple'
}
var mapvLayer = new mapv.baiduMapLayer(this.map, dataSet, options);
},
航线图
/**
* 绘制航线图
*/
drawHangxian(scenicSpot) {
var to = '重庆';
var qianxi = new mapv.DataSet(scenicSpot);
var qianxiData = qianxi.get();
var lineData = [];
var pointData = [];
var textData = [];
var timeData = [];
var citys = {}
for (var i = 0; i < qianxiData.length; i++) {
var fromCenter = mapv.utilCityCenter.getCenterByCityName(qianxiData[i].from);
var toCenter = mapv.utilCityCenter.getCenterByCityName(to);
if (!fromCenter || !toCenter) {
continue;
}
citys[qianxiData[i].from] = qianxiData[i].count;
citys[to] = 100;
pointData.push(
{
geometry: {
type: 'Point',
coordinates: [fromCenter.lng, fromCenter.lat]
}
}
);
pointData.push(
{
geometry: {
type: 'Point',
coordinates: [toCenter.lng, toCenter.lat]
}
}
);
textData.push(
{
geometry: {
type: 'Point',
coordinates: [fromCenter.lng, fromCenter.lat]
},
text: qianxiData[i].from
}
);
textData.push(
{
geometry: {
type: 'Point',
coordinates: [toCenter.lng, toCenter.lat]
},
text: to
}
);
var curve = mapv.utilCurve.getPoints([fromCenter, toCenter]);
for (var j = 0; j < curve.length; j++) {
timeData.push({
geometry: {
type: 'Point',
coordinates: curve[j]
},
count: 1,
time: j
});
}
lineData.push({
geometry: {
type: 'LineString',
coordinates: curve
//coordinates: [[fromCenter.lng, fromCenter.lat], [toCenter.lng, toCenter.lat]]
},
count: 30 * Math.random()
});
}
var textDataSet = new mapv.DataSet(textData);
var textOptions = {
draw: 'text',
font: '14px Arial',
fillStyle: 'white',
shadowColor: 'yellow',
shadowBlue: 10,
zIndex: 11,
shadowBlur: 10
}
var textMapvLayer = new mapv.baiduMapLayer(this.map, textDataSet, textOptions);
var lineDataSet = new mapv.DataSet(lineData);
var lineOptions = {
strokeStyle: 'rgba(255, 250, 50, 0.8)',
shadowColor: 'rgba(255, 250, 50, 1)',
shadowBlur: 20,
lineWidth: 2,
zIndex: 100,
draw: 'simple'
}
var lineLayer = new mapv.baiduMapLayer(this.map, lineDataSet, lineOptions);
// 描绘点
var pointOptions = {
fillStyle: 'rgba(254,175,3,0.7)',
shadowColor: 'rgba(55, 50, 250, 0.5)',
shadowBlur: 10,
size: 5,
zIndex: 10,
draw: 'simple'
}
var pointDataSet = new mapv.DataSet(pointData);
var pointLayer = new mapv.baiduMapLayer(this.map, pointDataSet, pointOptions);
// 动态效果
var timeDataSet = new mapv.DataSet(timeData);
var timeOptions = {
fillStyle: 'rgba(255, 250, 250, 0.5)',
zIndex: 200,
size: 2.5,
animation: {
type: 'time',
stepsRange: {
start: 0,
end: 50
},
trails: 10,
duration: 2,
},
draw: 'simple'
}
var timeMapvLayer = new mapv.baiduMapLayer(this.map, timeDataSet, timeOptions);
},
动态街道路径效果
/**
* 显示航线图
*/
showLinesOnMap(lines) {
// 重置地图样式
this.map.clearOverlays()
this.map.centerAndZoom(new BMap.Point(106.543254,29.556327), 14);
var data = [];
var timeData = [];
let rs = Object.keys(lines).map(function (key) {
return lines[key]
})
for (var i = 0; i < rs.length; i++) {
var item = rs[i]
var coordinates = [];
for (let j = 0; j < item.length; j++) {
coordinates.push([Number.parseFloat(item[j].lng), Number.parseFloat(item[j].lat)]);
timeData.push({
geometry: {
type: 'Point',
coordinates: [Number.parseFloat(item[j].lng), Number.parseFloat(item[j].lat)]
},
count: 1,
time: j
});
}
data.push({
geometry: {
type: 'LineString',
coordinates: coordinates
}
});
}
var dataSet = new mapv.DataSet(data);
var options = {
strokeStyle: 'rgba(53,57,255,0.5)',
coordType: 'bd09mc',
// globalCompositeOperation: 'lighter',
shadowColor: 'rgba(53,57,255,0.2)',
shadowBlur: 3,
lineWidth: 3.0,
draw: 'simple'
}
var mapvLayer = new mapv.baiduMapLayer(this.map, dataSet, options);
var dataSet = new mapv.DataSet(timeData);
var options = {
fillStyle: 'rgba(255, 250, 250, 0.2)',
coordType: 'bd09mc',
globalCompositeOperation: "lighter",
size: 1.5,
animation: {
stepsRange: {
start: 0,
end: 100
},
trails: 3,
duration: 5,
},
draw: 'simple'
}
var mapvLayer = new mapv.baiduMapLayer(this.map, dataSet, options);
},
附:经纬度坐标转墨卡托坐标
在做mapv街道路径图的时候,发现无法直接使用普通经纬度数据,进行街道路径绘制,需要将原有经纬度坐标转换墨卡托坐标。以下附转换函数供参考使用。
export default {
x_pi: 3.14159265358979324 * 3000.0 / 180.0,
LLBAND: [75, 60, 45, 30, 15, 0],
LL2MC: [
[-0.0015702102444, 111320.7020616939, 1704480524535203, -10338987376042340, 26112667856603880, -35149669176653700, 26595700718403920, -10725012454188240, 1800819912950474, 82.5],
[0.0008277824516172526, 111320.7020463578, 647795574.6671607, -4082003173.641316, 10774905663.51142, -15171875531.51559, 12053065338.62167, -5124939663.577472, 913311935.9512032, 67.5],
[0.00337398766765, 111320.7020202162, 4481351.045890365, -23393751.19931662, 79682215.47186455, -115964993.2797253, 97236711.15602145, -43661946.33752821, 8477230.501135234, 52.5],
[0.00220636496208, 111320.7020209128, 51751.86112841131, 3796837.749470245, 992013.7397791013, -1221952.21711287, 1340652.697009075, -620943.6990984312, 144416.9293806241, 37.5],
[-0.0003441963504368392, 111320.7020576856, 278.2353980772752, 2485758.690035394, 6070.750963243378, 54821.18345352118, 9540.606633304236, -2710.55326746645, 1405.483844121726, 22.5],
[-0.0003218135878613132, 111320.7020701615, 0.00369383431289, 823725.6402795718, 0.46104986909093, 2351.343141331292, 1.58060784298199, 8.77738589078284, 0.37238884252424, 7.45]
],
getRange(cC, cB, T) {
if (cB != null) {
cC = Math.max(cC, cB);
}
if (T != null) {
cC = Math.min(cC, T);
}
return cC;
},
getLoop(cC, cB, T) {
while (cC > T) {
cC -= T - cB;
}
while (cC < cB) {
cC += T - cB;
}
return cC;
},
convertor(cC, cD) {
if (!cC || !cD) {
return null;
}
let T = cD[0] + cD[1] * Math.abs(cC.x);
const cB = Math.abs(cC.y) / cD[9];
let cE = cD[2] + cD[3] * cB + cD[4] * cB * cB +
cD[5] * cB * cB * cB + cD[6] * cB * cB * cB * cB +
cD[7] * cB * cB * cB * cB * cB +
cD[8] * cB * cB * cB * cB * cB * cB;
T *= (cC.x < 0 ? -1 : 1);
cE *= (cC.y < 0 ? -1 : 1);
return [T, cE];
},
/// 经纬度坐标转墨卡托坐标
convertLL2MC(T) {
let cD, cC, len;
T.x = this.getLoop(T.x, -180, 180);
T.y = this.getRange(T.y, -74, 74);
const cB = T;
for (cC = 0, len = this.LLBAND.length; cC < len; cC++) {
if (cB.y >= this.LLBAND[cC]) {
cD = this.LL2MC[cC];
break;
}
}
if (!cD) {
for (cC = this.LLBAND.length - 1; cC >= 0; cC--) {
if (cB.y <= -this.LLBAND[cC]) {
cD = this.LL2MC[cC];
break;
}
}
}
const cE = this.convertor(T, cD);
return cE;
}
}