首先需要一段热力信息的json,我放在头部了。
然后就是需要de-geo库了。
实现代码如下:
javascript
import * as d3geo from 'd3-geo'
import trafficJSON from '../assets/json/traffic.json'
let geoFun;// 地理投影函数
//
let info = {
max: Number.MIN_SAFE_INTEGER,
min: Number.MAX_SAFE_INTEGER,
maxlng: Number.MIN_SAFE_INTEGER,
minlng: Number.MAX_SAFE_INTEGER,
maxlat: Number.MIN_SAFE_INTEGER,
minlat: Number.MAX_SAFE_INTEGER,
data: []
};
// 初始化地理投影
const initGeo = (size) => {
geoFun = d3geo.geoMercator().scale(size || 100)
}
// 经纬度转像素坐标
const latlng2px = (pos) => {
if (pos[0] >= -180 && pos[0] <= 180 && pos[1] >= -90 && pos[1] <= 90) {
return geoFun(pos);
}
return pos;
};
// 创建颜色
const createColors = (option) => {
const canvas = document.createElement('canvas');
document.body.appendChild(canvas);
const ctx = canvas.getContext('2d');
canvas.width = 256;
canvas.height = 1;
const grad = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
for (let k in option.colors) {
grad.addColorStop(k, option.colors[k]);
}
ctx.fillStyle = grad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
return ctx.getImageData(0, 0, canvas.width, 1).data;
}
// 绘制圆
const drawCircle = (ctx, option, item) => {
let { lng, lat, value } = item;
let x = lng - option.minlng + option.radius;
let y = lat - option.minlat + option.radius;
const grad = ctx.createRadialGradient(x, y, 0, x, y, option.radius);
grad.addColorStop(0.0, 'rgba(0,0,0,1)');
grad.addColorStop(1.0, 'rgba(0,0,0,0)');
ctx.fillStyle = grad;
ctx.beginPath();
ctx.arc(x, y, option.radius, 0, 2 * Math.PI);
ctx.closePath();
ctx.globalAlpha = (value - option.min) / option.size;
ctx.fill();
}
// 创建热力图
const createHeatmap = (option) => {
const canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.width = option.width;
canvas.height = option.height;
const ctx = canvas.getContext('2d');
option.size = option.max - option.min;
option.data.forEach((item) => {
drawCircle(ctx, option, item);
});
const colorData = createColors(option);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
for (let i = 3; i < imageData.data.length; i = i + 4) {
let opacity = imageData.data[i];
let offset = opacity * 4;
//red
imageData.data[i - 3] = colorData[offset];
//green
imageData.data[i - 2] = colorData[offset + 1];
//blue
imageData.data[i - 1] = colorData[offset + 2];
}
ctx.putImageData(imageData, 0, 0);
}
// 初始化
const init = () => {
initGeo(1000)
// 处理数据
trafficJSON.features.forEach((item) => {
let pos = latlng2px(item.geometry.coordinates);// 经纬度转像素坐标
let newitem = {
lng: pos[0],
lat: pos[1],
value: item.properties.avg
}
info.max = Math.max(newitem.value, info.max);
info.maxlng = Math.max(newitem.lng, info.maxlng);
info.maxlat = Math.max(newitem.lat, info.maxlat);
info.min = Math.min(newitem.value, info.min);
info.minlng = Math.min(newitem.lng, info.minlng);
info.minlat = Math.min(newitem.lat, info.minlat);
info.data.push(newitem);
})
info.size = info.max - info.min;
info.sizelng = info.maxlng - info.minlng;
info.sizelat = info.maxlat - info.minlat;
const radius = 50;
createHeatmap({
width: info.sizelng + radius * 2,
height: info.sizelng + radius * 2,
colors: {
0.1: '#2A85B8',
0.2: '#16B0A9',
0.3: '#29CF6F',
0.4: '#5CE182',
0.5: '#7DF675',
0.6: '#FFF100',
0.7: '#FAA53F',
1: '#D04343'
},
radius,
...info
})
}
init();