text arcgis for js 4.x集成热力图

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了text arcgis for js 4.x集成热力图相关的知识,希望对你有一定的参考价值。

## arcgis for js 4.x集成热力图

####  主要步骤
1. [引入热力图插件 heatmap.js](#wendang)
2. [引入arcgis for js热力图集成工具](#tools)
3. [创建热力图图层](#create)
4. [获取数据,生成热力图](#getData)
5. [API](#API)


---

##### <span id="wendang">一、引入热力图插件 heatmap.js</span>
相关文档地址  
[github-heatmap](https://github.com/pa7/heatmap.js)   
[官方网站](https://www.patrick-wied.at/static/heatmapjs/)  
[CSDN相关资料](http://blog.csdn.net/rongchaoliu/article/details/47830799)

---
##### <span id="tools">二、引入arcgis for js热力图集成工具</span>


~~~JavaScript

var HeartMapLayer;
function initHeartMapLayer(createHeatMapLayer) {
    require([
        "esri/layers/BaseDynamicLayer",
        "esri/request"
    ], function (
        BaseDynamicLayer, esriRequest
    ) {
        HeartMapLayer = BaseDynamicLayer.createSubclass({
            properties: {},
            heatMap: null,
            // 构造方法
            constructor: function (properties) {
                dojo.safeMixin(this.properties, properties);

                //设置图层的ID
                id : properties.id || null,
                // 热力图创建所在的view
                this._view = this.properties.view;
                // 最终数据存储
                this.lastData = [];
                // 热力图所在dom
                this.domNode = document.getElementById(this.properties.domNodeId);
                // 初始化参数
                this.config = {
                    container : this.domNode,
                    width: this._view.width,
                    height: this._view.height,
                    radius: 40,
                    debug: false,
                    visible: true,
                    useLocalMaximum: false,
                    gradient: {
                        0.45: "rgb(000,000,255)",
                        0.55: "rgb(000,255,255)",
                        0.65: "rgb(000,255,000)",
                        0.95: "rgb(255,255,000)",
                        1.00: "rgb(255,000,000)"
                    }
                };
                // 创建热力图
                this.heatMap = h337.create(this.config);
                // loaded
                this.loaded = true;
                // this.onLoad(this);
                // global maximum value
                this.globalMax = 0;

                //添加视图resize事件,调整heatmap尺寸
                // view.on("resize", function (event) {
                //     this.resizeHeatmap(event);
                // });
                dojo.connect(this._view, "onresize", this, this.resizeHeatmap);

                // heatlayer div styling
                this.domNode.style.position = 'relative';
                this.domNode.style.display = 'none';

                //TODO 绑定图层移除事件,待完善(延迟执行不确定性太多,但是未找到方法)
                this.on("layerview-destroy", function (event) {
                    setTimeout(function (layer) {
                        layer.view.map.add(layer);
                    }, 500, this);
                });
            },
            resizeHeatmap: function (event) {
                var width = event.width;
                var height = event.height;
                //设置画布宽高
                this.heatMap._renderer.setDimensions(width, height);
                // 设置热力图容器的宽高
                dojo.style(this.domNode, {
                    "width": width + 'px',
                    "height": height + 'px'
                });
                // set width and height of canvas element inside of container
                var child = dojo.query(':first-child', this.domNode);
                if (child) {
                    child.attr('width', width);
                    child.attr('height', height);
                }
            },
            //将转换后的数据设置到热力图
            storeHeatmapData: function (heatPluginData) {
                // 设置热力图的数据
                this.heatMap.setData(heatPluginData);
            },
            // 按照热力图插件的数据格式转换数据
            convertHeatmapData: function (parsedData) {
                var xParsed, yParsed, heatPluginData, dataPoint, screenGeometry;
                // 设置热力图插件的数据对象
                heatPluginData = {
                    max: parsedData.max,
                    data: []
                };
                if (parsedData.data) {
                    for (xParsed in parsedData.data) {
                        if (parsedData.data.hasOwnProperty(xParsed)) {
                            // for all y values and count
                            for (yParsed in parsedData.data[xParsed]) {
                                if (parsedData.data[xParsed].hasOwnProperty(yParsed)) {
                                    // 将经纬度作为转为屏幕XY坐标
                                    screenGeometry = view.toScreen(parsedData.data[xParsed][yParsed].dataPoint);
                                    // 将格式化后的数据放入数据集中
                                    heatPluginData.data.push({
                                        x: screenGeometry.x,
                                        y: screenGeometry.y,
                                        value: parsedData.data[xParsed][yParsed].heatValue // count value of x,y
                                    });
                                }
                            }
                        }
                    }
                }
                //将格式化后的数据设置到热力图并渲染
                this.storeHeatmapData(heatPluginData);
            },
            // 格式化数据,并获取最大值
            parseHeatmapData: function (features) {
                // variables
                var i, parsedData, dataPoint, attributes;
                // if data points exist
                if (features) {
                    // create parsed data object
                    parsedData = {
                        max: 0,
                        data: []
                    };
                    if (!this.config.useLocalMaximum) {
                        parsedData.max = this.globalMax;
                    }
                    // 遍历每一个坐标点
                    for (i = 0; i < features.length; i++) {
                        // 获取电信系
                        dataPoint = features[i].geometry;
                        // dataPoint = esri.geometry.Point(features[i].geometry);
                        // 检查点是否有效
                        var validPoint = false;
                        // 如果不使用设置的最大值, 点是有效的
                        if (!this.config.useLocalMaximum) {
                            validPoint = true;
                        }
                        // 如果使用设置的最大值,要确保点在当前视图内
                        else if(this._view.extent.contains(dataPoint)){
                            validPoint = true;
                        }
                        if (validPoint) {
                            attributes = features[i].attributes;
                            if (!parsedData.data[dataPoint.x]) {
                                parsedData.data[dataPoint.x] = [];
                            }
                            // 如果X,Y数据未创建,则创建
                            if (!parsedData.data[dataPoint.x][dataPoint.y]) {
                                // 创建一个数据对象
                                parsedData.data[dataPoint.x][dataPoint.y] = {};
                                // 如果热力图渲染属性在地图数据中存在,则使用地图数据
                                if (attributes && attributes.hasOwnProperty('heatValue')) {
                                    parsedData.data[dataPoint.x][dataPoint.y].heatValue = attributes.heatValue;
                                } else {
                                    parsedData.data[dataPoint.x][dataPoint.y].heatValue = 0;
                                }
                            }
                            // 渲染属性数据+1
                            parsedData.data[dataPoint.x][dataPoint.y].heatValue += 1;
                            // 添加经纬度点数据,用于下一步计算屏幕坐标
                            parsedData.data[dataPoint.x][dataPoint.y].dataPoint = dataPoint;
                            // 获取最大值
                            if (parsedData.max < parsedData.data[dataPoint.x][dataPoint.y].heatValue) {
                                parsedData.max = parsedData.data[dataPoint.x][dataPoint.y].heatValue;
                                if (!this.config.useLocalMaximum) {
                                    this.globalMax = parsedData.data[dataPoint.x][dataPoint.y].heatValue;
                                }
                            }

                        }
                    }
                    //按照热力图插件所需的数据格式进一步转换数据
                    this.convertHeatmapData(parsedData);
                }
            },
            // 设置数据
            setData: function (features) {
                // 设置地图的宽高
                var event = {width : this._view.width, height : this._view.height}
                this.resizeHeatmap(event);
                // 设置数据
                this.lastData = features;
                // this.parseHeatmapData(features);
                //重新描画图层,refresh方法在3D地图下无效,解决方案采用添加移除图层来解决
                var viewType = this.view.type;
                if (viewType == "3d") {
                    //TODO 移除图层,待完善(图层如果不在map中,如何处理?)
                    //该方法存在回调,移除后执行添加图层操作
                    this.view.map.remove(this);
                } else {
                    // 重新描画图层(此方法在3D地图下无效)
                    this.refresh();
                }
            },
            // 添加一个元素到热力图,并重新描画热力图
            addDataPoint: function (feature) {
                if (feature) {
                    // 将数据添加到最终数据
                    this.lastData.push(feature);
                    // 设置数据
                    setData(this.lastData);
                }
            },
            // 返回生成热力图的数据集合
            exportDataSet: function () {
                return this.lastData;
            },
            // TODO 清除数据
            clearData: function () {
                //清除热力图的数据
                this.heatMap.removeData();
                // this.heatMap.clear();
                var empty = [];
                //设置热力图数据未[],并重新描画
                this.setData(empty);
            },
            // 获取图片二进制数据
            getImageUrl: function (extent, width, height) {
                // 始终最终数据创建热力图
                this.parseHeatmapData(this.lastData);
                // 获取生成的热力图图片信息
                var imageUrl = this.heatMap.getDataURL();
                return imageUrl;
            },
            //图片预处理,将二进制数据转为图片
            fetchImage : function (extent, width, height) {
                var url = this.getImageUrl(extent, width, height);
                return esriRequest(url, {
                    responseType: "image",
                    allowImageDataAccess: true
                })
                    .then(function(response) {
                        var image = response.data;

                        var canvas = document.createElement("canvas");
                        var context = canvas.getContext("2d");
                        canvas.width = width;
                        canvas.height = height;

                        //TODO 存在问题:width、height值为2048(原因不明),而热力图画板宽高为视图view宽高,直接放到视图则热力图会放大,计算宽高的差值,将热力图便宜解决上述问题
                        //计算X Y
                        var x = (width - this._view.width) / 2;
                        var y = (height - this._view.height) / 2;
                        context.drawImage(image, x, y, this._view.width, this._view.height);
                        return canvas;
                    }.bind(this));
            }
        });
        createHeatMapLayer();
    });
}
~~~


---
##### <span id="create">三、创建热力图图层</span>
1、视图创建完成之后执行,热力图初始化,并传入图层创建函数作为回调函数,热力图初始化完毕后创建热力图图层
~~~JavaScript
//初始化热力图,视图创建完毕后执行
initHeartMapLayer(createHeatMapLayer);

/**
 * 创建热力图
 */
function createHeatMapLayer() {
    heatLayer = new HeartMapLayer({
        config: {
            "useLocalMaximum": true,
            "radius": 40,
            "gradient": {
                0.45: "rgb(000,000,255)",
                0.55: "rgb(000,255,255)",
                0.65: "rgb(000,255,000)",
                0.95: "rgb(255,255,000)",
                1.00: "rgb(255,000,000)"
            }
        },
        id : "heatLayer",
        "view": view,
        "domNodeId": "heatLayer",
        "opacity": 0.85
    });
    map.add(heatLayer);
}
~~~


---
##### <span id="getData">四、获取数据,生成热力图</span>
获取数据生成热力图,数据未arcgis点元素集合,调用setData函数设置数据,生成热力图

##### <span id="API">五、API</span>

Name | Parameter | Return Type | Summary
---|--- | ---|---
setData | [arcgis for js point元素集合](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Point.html) | 无 | 设置热力图数据,并刷新热力图图层
addDataPoint | [arcgis for js point元素](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Point.html) | 无 | 添加一个元素到热力图,并重新描画热力图
exportDataSet | 无 | [arcgis for js point元素集合](https://developers.arcgis.com/javascript/latest/api-reference/esri-geometry-Point.html) | 返回生成热力图的数据
clearData | 无 | 无 | 清除热力图数据,并清除热力图

以上是关于text arcgis for js 4.x集成热力图的主要内容,如果未能解决你的问题,请参考以下文章

arcgis api 4.x for js 集成 Echarts4 实现模拟迁徙图效果(附源码下载)

arcgis api 4.x for js之图层管理篇

arcgis for js 4.X 鼠标悬停弹出气泡

arcgis for js 4.X 鼠标悬停弹出气泡

arcgis api 4.x for js 聚合效果图(附源码下载)

arcgis api 4.x for js之图层管理篇