json绘制热力图

首先需要一段热力信息的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();
相关推荐
Yaml42 分钟前
Java的六大排序
java·算法·排序算法
九年义务漏网鲨鱼24 分钟前
【人脸伪造检测后门攻击】 Exploring Frequency Adversarial Attacks for Face Forgery Detection
论文阅读·python·算法·aigc
FIRE25 分钟前
uniapp小程序分享使用canvas自定义绘制 vue3
前端·小程序·uni-app
四喜花露水26 分钟前
vue elementui el-dropdown-item设置@click无效的解决方案
前端·vue.js·elementui
_OLi_30 分钟前
力扣 LeetCode 977. 有序数组的平方(Day1:数组)
数据结构·算法·leetcode
励志成为嵌入式工程师1 小时前
c语言选择排序
c语言·算法·排序算法
jokerest1231 小时前
web——sqliabs靶场——第五关——报错注入和布尔盲注
前端
風清掦1 小时前
C/C++每日一练:编写一个查找子串的位置函数
c语言·c++·算法
A charmer1 小时前
算法每日双题精讲——滑动窗口(最大连续1的个数 III,将 x 减到 0 的最小操作数)
c++·算法·leetcode
谢尔登1 小时前
前端开发调试之 PC 端调试
开发语言·前端