1 Star 0 Fork 1

沉淀 / Visualization

forked from 暖风 / Visualization 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

leaflet-viz

Leaflet可视化平台

leaflet是一个开源的前端地图交互类库,比较轻量级,支持移动端。而且有丰富的插件资源可供我们使用。

Echarts是百度开源的前端可视化类库,提供丰富的前端可视化图表,平台中重要的一部分是我们要将leaflet和Echarts结合在一起。

该平台是基于leaflet及其插件搭建的一个方便可用的可视化平台。详细参见[示例Demo]。(https://zrysmt.github.io/demo/leaflet-demo/)

1. 安装与编译

  • 安装
npm install
  • 编译

debug模式

npm run dev

输出

npm run build

2.示例简介

示例地址:https://zrysmt.github.io/demo/leaflet-demo/ 示例包含最基本的GIS功能和可视化Demo

3.基础的GIS功能

  • 拖放、全图、定位、打印出图片、打印出PDF功能。
  • 地图缩放、比例尺显示功能
  • 测量面积和距离功能
  • 图层切换,提供丰富的图层切换
  • 地图搜索功能
  • 基础绘图功能

4.可视化示例

  • 热力图

引入:

import '../common/leaflet-plugin/HeatLayer.js';

使用:

var heat = L.heatLayer([
    [50.5, 30.5, 0.2], // lat, lng, intensity
    [50.6, 30.4, 0.5],
...
], {radius: 25}).addTo(map)

效果图

  • 结合Echarts
let overlay = new L.echartsLayer3(map, echarts);
let chartsContainer = overlay.getEchartsContainer();
let myChart = overlay.initECharts(chartsContainer);
window.onresize = myChart.onresize;
console.log("chartsContainer:", chartsContainer);
if (type == "qianxi") {
    overlay.setOption(ecOption);
} else if (type == "scatter") {
    overlay.setOption(scatterOption);
}

迁徙图(选择了高德卫星底图) 散点图(选择了Geoq午夜蓝底图)

  • DivIcon结合Echarts

这个方案不太适合大数据量的渲染。 我写了两个简单的功能函数,一个用来渲染可视化图(echartsIcon),一个专门用来渲染图例(echartsLegend)。 效果图(底图选择了为google底图)

import echartsIcon from '../common/plugin/echartsIcon.js'; //echartsLegend
import echartsLegend from '../common/plugin/echartsLegend.js'; //echartsLegend
let option = {
    tooltip: {
        trigger: 'item',
        formatter: "{a} <br/>{b} : {c} ({d}%)"
    },
    series: [{
        name: '访问来源',
        type: 'pie',
        radius: '55%',
        center: ['50%', '50%'],
        label: {
            normal: {
                show: false
            },
            emphasis: {
                show: false
            }
        },
        lableLine: {
            normal: {
                show: false
            },
            emphasis: {
                show: false
            }
        },
        itemStyle: {
            emphasis: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: 'rgba(0, 0, 0, 0.5)'
            }
        }
    }]
};
//经纬度不能相同
let latlngs = [
    [30, 104],
    [31, 110],
    [34, 120]
];
option.datas = [
    [
        { value: 335, name: '直接访问' },
        { value: 310, name: '邮件营销' },
        { value: 234, name: '联盟广告' },
        { value: 135, name: '视频广告' },
        { value: 1548, name: '搜索引擎' }
    ],
    [
        { value: 345, name: '直接访问' },
        { value: 410, name: '邮件营销' },
        { value: 244, name: '联盟广告' },
        { value: 145, name: '视频广告' },
        { value: 548, name: '搜索引擎' }
    ],
    [
        { value: 445, name: '直接访问' },
        { value: 410, name: '邮件营销' },
        { value: 244, name: '联盟广告' },
        { value: 145, name: '视频广告' },
        { value: 148, name: '搜索引擎' }
    ],
];
echartsIcon(map, latlngs, option);
//图例
let legendOption = {
    orient: 'vertical',
    left: 'left',
    width: "90px",
    height: "140px",
    data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
};
echartsLegend(map, legendOption);
  • leaflet-dvf

leaflet-dvf是一个基于leaflet的数据可视化框架,提供有比较多的可视化图形。

import "../common/leaflet-plugin/Leaflet.dvf/css/dvf.css";
import "leaflet-dvf";

地震图: 收入水平图: 需要的数据

import earthquakesData from '../data/earthquakes.json';
import countryData from '../data/countryData.js';

地震图代码:

 let lastLayer;

 let eqfeed_callback = function(data) {

     // Initialize framework linear functions for mapping earthquake data properties to Leaflet style properties
     // Color scale - green to red using the basic HSLHueFunction
     let magnitudeColorFunction = new L.HSLHueFunction(new L.Point(0, 90), new L.Point(10, 0), { outputSaturation: '100%', outputLuminosity: '25%', postProcess: null });
     let magnitudeFillColorFunction = new L.HSLHueFunction(new L.Point(0, 90), new L.Point(10, 0), { outputSaturation: '100%', outputLuminosity: '50%', postProcess: null });
     let magnitudeRadiusFunction = new L.LinearFunction(new L.Point(0, 10), new L.Point(10, 30), { postProcess: null });

     let now = Math.round((new Date()).getTime());
     let start = now - 86400000;

     // Initialize a linear function to map earthquake time to opacity
     let timeOpacityFunction = new L.LinearFunction(new L.Point(start, 0.3), new L.Point(now, 1));
     let fontSizeFunction = new L.LinearFunction(new L.Point(0, 8), new L.Point(10, 24));

     let textFunction = function(value) {
         return {
             text: value,
             style: {
                 'font-size': fontSizeFunction.evaluate(value)
             }
         };
     };

     // Setup a new data layer
     let dataLayer = new L.DataLayer(data, {
         recordsField: 'features',
         latitudeField: 'geometry.coordinates.1',
         longitudeField: 'geometry.coordinates.0',
         locationMode: L.LocationModes.LATLNG,
         displayOptions: {
             'properties.mag': {
                 displayName: '震级',
                 color: magnitudeColorFunction,
                 fillColor: magnitudeFillColorFunction,
                 radius: magnitudeRadiusFunction,
                 text: textFunction
             },
             'properties.time': {
                 displayName: '时间',
                 opacity: timeOpacityFunction,
                 fillOpacity: timeOpacityFunction,
                 displayText: function(value) {
                     return moment.unix(value / 1000).format('MM/DD/YY HH:mm');
                 }
             }
         },
         layerOptions: {
             numberOfSides: 4,
             radius: 10,
             weight: 1,
             color: '#000',
             opacity: 0.2,
             stroke: true,
             fillOpacity: 0.7,
             dropShadow: true,
             gradient: true
         },
         tooltipOptions: {
             iconSize: new L.Point(90, 90), //hover框大小
             iconAnchor: new L.Point(-4, 76)
         },
         onEachRecord: function(layer, record, location) {
             let $html = $(L.HTMLUtils.buildTable(record));

             layer.bindPopup($html.wrap('<div/>').parent().html(), {
                 minWidth: 400,
                 maxWidth: 400
             });
         }
     });

     // Add the data layer to the map
     map.addLayer(dataLayer);

     lastLayer = dataLayer;
 };

 this.mapSetting();

 if (lastLayer) {
     map.removeLayer(lastLayer);
 }

 console.log("earthquakesData:", earthquakesData);
 eqfeed_callback(earthquakesData)

收入水平图代码:

let incomeLevelTypes = ['OEC', 'NOC', 'UMC', 'MIC', 'LMC', 'LIC', 'HPC'];
let valueArray = [{ "id": "HIC", "value": "高收入(HIC)" },
    { "id": "HPC", "value": "收入严重不足(HIPC)" }, { "id": "INX", "value": "未分类(INX)" },
    { "id": "LIC", "value": "低收入(LIC)" }, { "id": "LMC", "value": "中等偏下(LMC)" },
    { "id": "LMY", "value": "中低等收入" }, { "id": "MIC", "value": "中等收入(MIC)" },
    { "id": "NOC", "value": "高收入:nonOECD(NOC)" }, { "id": "OEC", "value": "高收入: OECD(OEC)" },
    { "id": "UMC", "value": "中等偏上(UMC)" }
];
let getMap = function(valueArray) {
    let map = {};
    for (let index = 0; index < valueArray.length; ++index) {
        let value = valueArray[index];

        map[value['id']] = value['value'];
    }
    return map;
};

let valueMap = getMap(valueArray);

let incomeLevelToText = function(value) {
    return valueMap[incomeLevelTypes[value]];
};

let colorFunction1 = new L.HSLLuminosityFunction(new L.Point(0, 0.2), new L.Point(incomeLevelTypes.length - 1, 0.75), { outputHue: 0, outputLuminosity: '100%' });
let fillColorFunction1 = new L.HSLLuminosityFunction(new L.Point(0, 0.5), new L.Point(incomeLevelTypes.length - 1, 1), { outputHue: 0, outputLuminosity: '100%' });

let styles = new L.StylesBuilder(incomeLevelTypes, {
    displayName: incomeLevelToText,
    color: colorFunction1,
    fillColor: fillColorFunction1
});

let options = {
    recordsField: '1',
    locationMode: L.LocationModes.COUNTRY,
    codeField: 'id',
    displayOptions: {
        'incomeLevel.id': {
            displayName: '收入水平',
            styles: styles.getStyles()
        }
    },
    layerOptions: {
        fillOpacity: 0.7,
        opacity: 1,
        weight: 1
    },
    tooltipOptions: {
        iconSize: new L.Point(100, 65),
        iconAnchor: new L.Point(-5, 65)
    },

    onEachRecord: function(layer, record) {
        let $html = $(L.HTMLUtils.buildTable(record));

        layer.bindPopup($html.wrap('<div/>').parent().html(), {
            maxWidth: 400,
            minWidth: 400
        });
    }
};

let incomeLayer = new L.ChoroplethDataLayer(incomeLevels, options);

let legendControl = new L.Control.Legend();

legendControl.addTo(map);
map.addLayer(incomeLayer);

5.GeoJSON

假设我们需要自己做个地图,然后加载到平台中。这个时候可以使用我们提供了编辑栏,编辑后会得到坐标,把坐标转成GeoJSON数据存到数据库中,下次加载的时候解析即可。 还可以使用GIS工具,做成GeoJSON的数据,然后使用下面的方法加载,详细说明的传送门在这,当然这包括MapServer的东西,我们将在第六部分有简要说明。 示例图: 引入数据:

import { json_china } from '../data/china.js';
function pop_0(feature, layer) {//部分有省略
    let popupContent = '<table>\
                    <tr>\
                        <td colspan="2">面积:' + (feature.properties['AREA'] !== null ? Autolinker.link(String(feature.properties['AREA'])) : '') + '</td>\
                    </tr>\
                    <tr>\
                        <td colspan="2">周长:' + (feature.properties['PERIMETER'] !== null ? Autolinker.link(String(feature.properties['PERIMETER'])) : '') + '</td>\
                    </tr>\
                    <tr>\
                        <td colspan="2">名称:' + (feature.properties['NAME'] !== null ? Autolinker.link(String(feature.properties['NAME'])) : '') + '</td>\
                    </tr>\
                </table>';
    layer.bindPopup(popupContent);
}

function style_0() {
    return {
        pane: 'pane_0',
        opacity: 1,
        color: 'rgba(0,0,0,0.494117647059)',
        dashArray: '',
        lineCap: 'butt',
        lineJoin: 'miter',
        weight: 1.0,
        fillOpacity: 1,
        fillColor: 'rgba(64,98,210,0.494117647059)',
    }
}
map.createPane('pane_0');
map.getPane('pane_0').style.zIndex = 400;
map.getPane('pane_0').style['mix-blend-mode'] = 'normal';
let layer_0 = new L.geoJson(json_china, {
    attribution: '<a href=""></a>',
    pane: 'pane_0',
    onEachFeature: pop_0,
    style: style_0
});

6.MapServer

再进一步,如果我们想要自己的地图服务器,这个时候就需要使用到了MapServer,具体的说明见传送门

有个示例在test文件夹下:leaflet-mapserver.html。注意这个是需要配置好服务器的,在这里直接预览是不能成功的。 示例得到我们的世界地图的地图服务器。

其实leaflet和D3等开源库结合起来,能得到很多丰富多彩的可视化图,姑且留下点神秘,这里就不再探究两者结合的神奇魅力了。

MIT License Copyright (c) 2017 Zhao Ruyi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

Leaflet可视化平台 展开 收起
JavaScript
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
JavaScript
1
https://gitee.com/complete_info/Visualization.git
git@gitee.com:complete_info/Visualization.git
complete_info
Visualization
Visualization
master

搜索帮助