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集成热力图的主要内容,如果未能解决你的问题,请参考以下文章