当前位置:网站首页>maptalks:数据归一化处理与分层设色图层加载

maptalks:数据归一化处理与分层设色图层加载

2022-06-24 19:03:00 似曾不相识

功能需求

    在地图功能开发过程中,有根据区划统计数值,实现分层设色的需求。如:有以下人口总数统计数据(其中AREA表示行政区划编码,POPDENSITY表示人口总数数值),现在需要根据人口总数,实现分层设色,来对人口空间分布特征进行可视化展示。

{
    
    "msg": "返回成功",
    "data": [
        {
     "AREA": "310101", "POPDENSITY": 32295 },
        {
     "AREA": "310104", "POPDENSITY": 20177 },
        {
     "AREA": "310105", "POPDENSITY": 18651 },
        {
     "AREA": "310106", "POPDENSITY": 26533 },
        {
     "AREA": "310107", "POPDENSITY": 22325 },
        {
     "AREA": "310109", "POPDENSITY": 32387 },
        {
     "AREA": "310110", "POPDENSITY": 20517 },
        {
     "AREA": "310112", "POPDENSITY": 7115 },
        {
     "AREA": "310113", "POPDENSITY": 7407 },
        {
     "AREA": "310114", "POPDENSITY": 3960 },
        {
     "AREA": "310115", "POPDENSITY": 4071 },
        {
     "AREA": "310116", "POPDENSITY": 1356 },
        {
     "AREA": "310117", "POPDENSITY": 3158 },
        {
     "AREA": "310118", "POPDENSITY": 1902 },
        {
     "AREA": "310120", "POPDENSITY": 1597 },
        {
     "AREA": "310151", "POPDENSITY": 470 }
    ]
}

实现思路

色带选取

    分层设色,实质上就是根据不同的权重值,来选择不同轻重程度的数量值,通过颜色的变化,来反映数值的变化。映射到地理空间,就是为了展示数值在空间分布上的变化情况。色带如何选择?可以点击此处,通过Color Blender在线工具生成。以下是我设计的色带,对应的颜色代码数组如下,长度为10,

  const colortable_3 = [
            "#FFFFCC",
            "#FFF1B9",
            "#FFE3A7",
            "#FFD594",
            "#FFC782",
            "#FFB96F",
            "#FFAC5D",
            "#FF9E4A",
            "#FF9038",
            "#FF8225",
            "#FF7413",
            "#FF6600"
        ]

在这里插入图片描述

数据处理

    如何将统计数据映射到色彩空间呢?由于色带数组长度为10,所以,可以先将原始数据做归一化处理,再将处理结果乘以10,向下取整,将计算结果作为colortable_3 数组的下标索引值,取到对应的16进制颜色代码。
    通过上述先归一化、再缩放的处理方式,即可将原始数据的变化映射到色彩空间的颜色变化。
    计算公式如下,
在这里插入图片描述

核心代码

    对应的核心计算代码,实现如下,

  /** * 加载上海市行政区划图-人口密度分层设色图 * */
    function loadSH_map(_map, _layerName, _dataSource, _boundValue, _colorTable = colortable_1) {
    
        let collection = new Array();
        // 遍历_dataSource数据源-重新设置symbol属性值
        _dataSource.some(function(value, index, array) {
    
            //获取行政区划编码
            let code = value.properties.adcode;
            //根据code获取对应的NUM值
            let curValue = getValueByAreaCode(code, _boundValue);
            //计算归一化值-整型数值
            let normalizationValue = Math.floor((curValue.POPDENSITY - _boundValue.min.POPDENSITY) / (_boundValue.max.POPDENSITY - _boundValue.min.POPDENSITY) * (_colorTable.length - 1));
            console.log(normalizationValue)
                //获取颜色表取值
            let fillColor = _colorTable[normalizationValue];
            //获取坐标数组
            let coordinates = value.geometry.coordinates;
            console.log(coordinates)
                //构造polygon多边形对象
            let polygon = new maptalks.MultiPolygon(coordinates, {
    
                visible: true,
                editable: true,
                cursor: 'pointer',
                shadowBlur: 0,
                shadowColor: 'black',
                draggable: false,
                dragShadow: false, // display a shadow during dragging
                drawOnAxis: null, // force dragging stick on a axis, can be: x, y
                symbol: {
    
                    'lineColor': '#34495e',
                    'lineWidth': 2,
                    'polygonFill': fillColor,
                    'polygonOpacity': 1
                }
            });
            collection.push(polygon);
        })
        new maptalks.VectorLayer('vector', new maptalks.GeometryCollection(collection))
            .addTo(_map);

    }

    /** * 根据行政区划编码获取对应的NUM值 * */
    function getValueByAreaCode(_code, _boundValue) {
    
        let result = boundValue.min;
        for (let i = 0; i < polulation.length; i++)
            if (polulation[i].AREA == _code) {
    
                result = polulation[i];
                break;
            }
        return result;
    }

完整示例代码

    以下为完整代码实现,如何对地理空间进行可视化呢?在此,选用maptalks二三维一体可视化平台,示例代码如下,

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>上海市分层设色</title>
    <!-- style内联样式 -->
    <style type="text/css">
        html,
        body {
    
            margin: 0px;
            height: 100%;
            width: 100%
        }
        
        .container {
    
            width: 100%;
            height: 100%;
        }
        /* 隐藏maptalks底部文字属性 */
        
        .maptalks-attribution {
    
            display: none;
        }
    </style>
    <!-- 引入maptalks资源 -->
    <link href="./plugins/maptalks.css" />
    <script src="./plugins/maptalks.js"></script>
    <!-- jquery -->
    <script src="./plugins/jquery-3.2.1.min.js"></script>
    <!-- 引入arcgis开发包 -->
    <script src="./plugins/arcgis/maptalks.arcgis.min.js"></script>
</head>

<body>
    <div id="map" class="container"></div>
</body>
<script>
    //创建基础图层
    let baseLayer = new maptalks.TileLayer('base', {
    
            urlTemplate: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
            subdomains: ['a', 'b', 'c', 'd'],
            // attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>',
            // css filter
            cssFilter: 'sepia(100%) invert(90%)',
            opacity: 0.95, // TileLayer's opacity, 0-1
        })
        //初始化maptalks
    var map = new maptalks.Map('map', {
    
        center: [121.467, 31.0334],
        zoom: 10,
        minZoom: 1, // set map's min zoom to 14
        maxZoom: 14, // set map's max zoom to 14
        // 拖动倾斜旋转参数
        //allow map to drag pitching, true by default
        dragPitch: true, //禁用抬起/相机pitch角度切换
        //allow map to drag rotating, true by default
        dragRotate: true, //false-禁用旋转
        //enable map to drag pitching and rotating at the same time, false by default
        dragRotatePitch: true, //
        doubleClickZoom: false, //取消鼠标双击放大效果
        baseLayer: baseLayer,
    });
    //挂载图层
    map.configLayers = {
    
        base_layer: baseLayer, //基础底图图层
        sh_layer: undefined, //基础矢量图层
        hhypsometric_layer: undefined, //热力图图层
    };

    //颜色表
    const colortable_3 = [
            "#FFFFCC",
            "#FFF1B9",
            "#FFE3A7",
            "#FFD594",
            "#FFC782",
            "#FFB96F",
            "#FFAC5D",
            "#FF9E4A",
            "#FF9038",
            "#FF8225",
            "#FF7413",
            "#FF6600"
        ]
        //获取人口数据+上海行政区划数据
    let polulation = getDataSource("people_num").data;
    let sh_dataSource = getDataSource("shanghai").features
    let sh_textSource = getDataSource("shanghai");
    //获取人口边界数据
    let boundValue = deal_populationData(polulation)
        //加载sh行政区划数据
    loadSH_map(map, "sh_layer", sh_dataSource, boundValue, colortable_3);
    //文字注记
    initMarker(map, sh_textSource);


    /** * 初始化中心标记点 * */
    function initMarker(_map, _dataSource) {
    
        //json转为geometry
        let geometries = maptalks.GeoJSON.toGeometry(_dataSource);
        let shptArray = new Array();
        //遍历geometries-添加中心标记点
        geometries.some(function(value, index, array) {
    
                let properties = value.properties; //获取属性数据
                shptArray.push(
                    new maptalks.Marker(properties.center, {
    
                        id: properties.name,
                        visible: true,
                        editable: true,
                        cursor: 'pointer',
                        shadowBlur: 0,
                        shadowColor: 'black',
                        draggable: false,
                        dragShadow: false, // display a shadow during dragging
                        drawOnAxis: null, // force dragging stick on a axis, can be: x, y
                        symbol: {
    
                            'textFaceName': 'sans-serif',
                            'textName': properties.name,
                            'textFill': '#fffff',
                            'textHorizontalAlignment': 'right',
                            'textSize': 16
                        },
                        properties: {
    
                            altitude: 2500,
                            properties: properties
                        }
                    })
                )
            })
            //创建geometryCollection集合
            //添加marker集合到VectorLayer中
        new maptalks.VectorLayer('vector_Marker', new maptalks.GeometryCollection(shptArray, {
    })).addTo(_map);

    }


     /** * 加载上海市行政区划图-人口密度分层设色图 * */
    function loadSH_map(_map, _layerName, _dataSource, _boundValue, _colorTable = colortable_1) {
    
        let collection = new Array();
        // 遍历_dataSource数据源-重新设置symbol属性值
        _dataSource.some(function(value, index, array) {
    
            //获取行政区划编码
            let code = value.properties.adcode;
            //根据code获取对应的NUM值
            let curValue = getValueByAreaCode(code, _boundValue);
            //计算归一化值-整型数值
            let normalizationValue = Math.floor((curValue.POPDENSITY - _boundValue.min.POPDENSITY) / (_boundValue.max.POPDENSITY - _boundValue.min.POPDENSITY) * (_colorTable.length - 1));
            console.log(normalizationValue)
                //获取颜色表取值
            let fillColor = _colorTable[normalizationValue];
            //获取坐标数组
            let coordinates = value.geometry.coordinates;
            console.log(coordinates)
                //构造polygon多边形对象
            let polygon = new maptalks.MultiPolygon(coordinates, {
    
                visible: true,
                editable: true,
                cursor: 'pointer',
                shadowBlur: 0,
                shadowColor: 'black',
                draggable: false,
                dragShadow: false, // display a shadow during dragging
                drawOnAxis: null, // force dragging stick on a axis, can be: x, y
                symbol: {
    
                    'lineColor': '#34495e',
                    'lineWidth': 2,
                    'polygonFill': fillColor,
                    'polygonOpacity': 1
                }
            });
            collection.push(polygon);
        })
        new maptalks.VectorLayer('vector', new maptalks.GeometryCollection(collection))
            .addTo(_map);

    }

    /** * 根据行政区划编码获取对应的NUM值 * */
    function getValueByAreaCode(_code, _boundValue) {
    
        let result = boundValue.min;
        for (let i = 0; i < polulation.length; i++)
            if (polulation[i].AREA == _code) {
    
                result = polulation[i];
                break;
            }
        return result;
    }

    //人口数据处理
    function deal_populationData(_population) {
    
        let boundValue = {
    };
        let minTemp = _population[0],
            maxTemp = _population[0];
        //计算最大最小值
        _population.some(function(value, index, array) {
    
            minTemp.POPDENSITY > value.POPDENSITY ? minTemp = value : "";
            maxTemp.POPDENSITY < value.POPDENSITY ? maxTemp = value : "";
        })
        return boundValue = {
    
            min: minTemp,
            max: maxTemp
        }
    }

    /** * 获取数据源 * */
    function getDataSource(_dataSource) {
    
        let dataSource = undefined;
        $.ajax({
    
            url: "./data/" + _dataSource + ".json",
            method: "GET",
            async: false,
            success: function(result, text, xhr) {
    
                //GeoJSON utilities-Convert one or more GeoJSON objects to geometry 
                dataSource = result;
            }
        });
        return dataSource;
    }
</script>

</html>

最终效果

    最终显示效果如下,
在这里插入图片描述

原网站

版权声明
本文为[似曾不相识]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_43524214/article/details/125432409