Openlayers 6.2.1 浅尝心得(三)

中国有句古话:“授之以鱼不如授之以渔”,所以今天我要记录的主要是关于 OpenLayers 的应用开发思路,而非某一具体的功能或代码。
OpenLayers 作为一个开源项目,我们首先需要知道的就是它的 官网源码地址。官网作为项目信息的集合地,对开发者来说是一个很好的了解项目的入口;而源码地址则可以帮助我们更好的了解代码逻辑,协助我们定位问题,解决问题。

天才第一步

打开官网,我们会发现对我们有用的部分有三块:在这里插入图片描述

第一部分:导航栏

导航栏有四个模块:文档(Docs)、示例(Examples)、接口(API)、源码(Code)。

  • 文档页:为我们介绍了如何入门、常见问题解答和更多问题。实用性不大,四舍五入可以忽略不计。
  • 示例页:很重要~!如果你是第一次接触 OpenLayers ,建议把示例页中的所有示例效果过一遍,好让我们对其能实现的基本功能有一个简单的了解。同时,示例代码也是我们在自己后续的项目开发过程中要经常参考的内容。
  • 接口页:重中之重~!!!各位程序员老哥,我想 API 的重要性就不用我说了吧。
  • 源码页:点击直接跳转至项目的 GitHub 地址。源码于博主而言,可以帮我更好的了解功能的实现思路,且在实际开发过程中,能够很好的帮我定位和解决部分疑难杂症。

第二部分:Hello World

首页的第二部分为我们留下了几个链接,通过他们我们很容易开始自己的开发。

Quick Start

这部分为快速开始,通常情况下是没有实用意义的,就像 Hello World 一样。打开页面,我们可以看到用传统方式搭建项目的示例。(这里不太推荐这种项目构建方式,因为如果真的使用这种非官方示例中的方式,会导致我们在后续的开发过程中遇到问题或开发新功能时,不容易调试或借鉴别人的方法)

Tutorials

这个部分为指南,点击链接后,我们可以看到四个部分:

  • 构建一个OpenLayers应用程序(介绍了如何在 Node 环境下构建一个 OpenLayers 应用程序,这是我们正确入门姿势)
  • 基本概念
  • OpenLayers的一些背景
  • 栅格投影

Workshop

这部分为一个为详细教程,点击链接后选择自己喜欢的语言(能看懂英文就不错了~!)进行更加系统的了解和学习。

第三部分:迭代史

第三部分,这里罗列了 OpenLayers 从第二版到第五版的相关内容和地址,为使用之前版本的老铁提供相关文档帮助。

甩代码

干聊了半天,是时候来的实际的了。以下代码为博主自己封装的部分功能函数,里面包含了:

  • 坐标系设置
  • 基础矢量图层对象的创建与加载
  • 自定义圆形特征层
  • 圆形特征层的样式设置
  • 圆形特征层的批量创建
  • 圆形图层的创建
  • 圆图层的动态添加
  • 点特征层的创建
  • 点特征层的样式设置
  • 点特征层的批量创建
  • 点图层的创建
  • 点图层的动态添加
  • Icon 选中高亮
  • overlay 图层创建(用于 Icon 鼠标悬浮事件效果)
  • 地图创建
  • 鼠标 hover 事件
  • 鼠标点击事件
  • 动态清除已渲染图层

olFun.js

// 导入 Openlayers 样式
import 'ol/ol.css';
// 导入 Icon 使用的图片
import dot_png from "../img/dot.png";
// 导入 Openlayers 模块
import {
    
    get, transform, fromLonLat} from 'ol/proj';
import Map from 'ol/Map'
import View from "ol/View";
import Feature from 'ol/Feature';
import {
    
    Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import TileWMS from 'ol/source/TileWMS';
import VectorSource from 'ol/source/Vector';
import Circle from "ol/geom/Circle";
import Point from 'ol/geom/Point';
import {
    
    Icon, Style, Fill, Stroke} from 'ol/style';
import Text from 'ol/style/Text';
import Overlay from 'ol/Overlay';
//  导入自定义函数
import {
    
    stationInfoLayers} from "./calledFunctions";
import {
    
    postAjax, replayEvent} from "./originFunctions";

// 创建墨卡托投影坐标系
const projection = get("EPSG:3857");
const vectorLayerArr = new Array();

// 创建基础矢量图层
const baseLayer = new TileLayer({
    
    
    source: new TileWMS({
    
    
        url: 'http://127.0.0.1:8080/***/services/Map/MapService/WMS',
        params: {
    
    LAYERS: 'Map', CRS: projection},
        projection: projection
    })
});
baseLayer.set("name", "BasicLayer", true);

// 创建圆形特征层
let createCircleFeature = function(coordinate, radius, name){
    
    
    if (!coordinate && !radius && !name){
    
    
        return null;
    }
    return new Feature({
    
    
        geometry: new Circle(transform(coordinate, "EPSG:4326", "EPSG:3857"), radius, "XY"),
        name: name
    })
};
// 创建圆形特征层样式
let createCircleStyle = function(color){
    
    
    if (!color){
    
    
        return null;
    }
    return new Style({
    
    
        // 设置填充颜色
        fill: new Fill({
    
    
            // 支持 CSS 中其他颜色设置方式 eg: 十六进制; rgb; rgba
            color: color
        })
    })
};
// 创建待渲染的点特征层数组
let createCircleFeatures = function(circles){
    
    
    let circleFeatures = [];
    $.each(circles, function (idx, item) {
    
    
        let circleFeature = createCircleFeature(item.coordinate, (item.radius)+10000, "circle" + idx);
        circleFeature.setStyle(createCircleStyle(item.color));
        circleFeatures.push(circleFeature);
    });
    return circleFeatures;
};
// 创建矢量圆图层
let createCircleVectorLayer = function(features){
    
    
    let circleLayer = new VectorLayer({
    
    
            source: new VectorSource({
    
    
                features: features
            }),
            opacity: 0.5
        });
    circleLayer.set("name", "CircleLayer", true);
    vectorLayerArr.push(circleLayer);
    map.addLayer(circleLayer);
};
// 渲染圆图层
let renderCircleLayer = function(circles){
    
    
    let circleFeatures = createCircleFeatures(circles);
    createCircleVectorLayer(circleFeatures);
};

// 创建点特征层
let createPointFeature  = function(coordinate, name){
    
    
    if (!coordinate && !name){
    
    
        return null;
    }
    return new Feature({
    
    
        geometry: new Point(fromLonLat(coordinate)),
        name: name
    })
};
// 创建点特征层样式
let createPointStyle = function(color, text, scale){
    
    
    let pointStyle = new Style({
    
    
        image: new Icon({
    
    
            color: color,
            crossOrigin: 'anonymous',
            // 对静态资源的引用需要引入,否则将无法把 js 中用到的图片编译至 dist 中
            src: dot_png,
            scale: scale
        })
    });
    // 设置点注记名称及其样式
    if(text){
    
    
        pointStyle.setText(new Text({
    
    
            text: text,
            textAlign: 'left',
            offsetX: 10,
            // 字体设置支持 CSS 通用字体设置方式
            font: "bold 20px 黑体,SimHei",
            fill: new Fill({
    
    
                color: color
            }),
            stroke: new Stroke({
    
    
                color: "#000000",
                width: 2
            })
        }))
    }
    return pointStyle;
};
// 创建待渲染的点特征层数组
let createPointFeatures = function(points){
    
    
    let pointFeatures = [];
    $.each(points, function (idx, item){
    
    
        let feature = createPointFeature([item.lon, item.lat], item.name);
        feature.setStyle(createPointStyle(item.color, item.text, item.scale));
        feature.setId(item.evid);
        feature.set("intensity", item.intensity, true);
        pointFeatures.push(feature);
    });
    return pointFeatures;
};
// 创建矢量点图层
let createPointsVectorLayer = function(features){
    
    
    let pointLayer = new VectorLayer({
    
    
        source: new VectorSource({
    
    
            features: features
        })
    });
    pointLayer.set("name", "PointLayer", true);
    pointLayer.setZIndex(1);
    vectorLayerArr.push(pointLayer);
    map.addLayer(pointLayer);
};
// 渲染点图层
let renderPointLayer = function (points) {
    
    
    let pointFeatures =  createPointFeatures(points);
    createPointsVectorLayer(pointFeatures);
};

// 这个函数有点牛逼——用来创建并渲染 Icon 的反色 Canvas 图片
let createAndRenderIconCanvasOverlay = function (feature) {
    
    
    if (feature) {
    
    
        var image = feature.getStyle().getImage().getImage();
        var canvas = document.createElement('canvas');
        var context = canvas.getContext('2d');
        canvas.width = image.width;
        canvas.height = image.height;
        context.drawImage(image, 0, 0, image.width, image.height);
        var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
        var data = imageData.data;
        for (var i = 0, ii = data.length; i < ii; i = i + (i % 4 == 2 ? 2 : 1)) {
    
    
            data[i] = 255 - data[i];
        }
        context.putImageData(imageData, 0, 0);
        feature.setStyle(new Style({
    
    
            image: new Icon({
    
    
                crossOrigin: 'anonymous',
                src: undefined,
                img: canvas,
                imgSize: canvas ? [canvas.width, canvas.height] : undefined,
            })
        }));
    }
};

// 创建 view
const view = new View({
    
    
    center: fromLonLat([105.14805, 35.26971]),
    projection: projection,
    zoom: 5,
    maxZoom: 14,
    minZoom: 4
});
// 创建 overlay
let element = document.getElementById('stationNamePopup');
let popup = new Overlay({
    
    
    element: element,
    positioning: 'bottom-center',
    stopEvent: false,
    offset: [0, -10]
});
// 创建 Map
const map = new Map({
    
    
    layers: [baseLayer],
    target: "sceneControlDiv",
    view: view,
    overlays: [popup],
    controls: []
});

// 鼠标 hover 事件
map.on('pointermove', function(evt) {
    
    
    let feature = map.forEachFeatureAtPixel(evt.pixel,
        function(feature) {
    
    
            return feature;
        });
    if (feature) {
    
    
        let coordinates = feature.getGeometry().getCoordinates();
        popup.setPosition(coordinates);
        let featureName = feature.get('name');
        if(featureName){
    
    
            element.innerHTML = `<div class="stationNameStyle">`+feature.get('name')+`</div>`;
        }
    } else {
    
    
        element.innerHTML = "";
    }
});

// 鼠标 click 事件
map.on('click', function(evt) {
    
    
    let feature = map.forEachFeatureAtPixel(evt.pixel,
        function(feature) {
    
    
            return feature;
        });
    if (feature) {
    
    
        let flag = feature.getId().split("_");
        // ↓↓↓↓↓↓↓↓↓↓----------  普通信息弹窗页面  ----------↓↓↓↓↓↓↓↓↓↓
        if (flag.length < 2) {
    
    
            layui.layer.closeAll('tips');
            stationInfoLayers(feature.getId(), feature.get('intensity'));
        } else if("1" === flag[0]){
    
    
            // ↓↓↓↓↓↓↓↓↓↓----------  事件回放  ----------↓↓↓↓↓↓↓↓↓↓
            let stations = postAjax("eventStation/selectByDateAndSource", false, 
                {
    
    "source":flag[1],"date":flag[2]});
            if(stations.length > 0){
    
    
                replayEvent(stations, flag[2], flag[1]);
            }
        }
    }
});

// 清除已渲染图层
function destoryVectorLayer(layerName) {
    
    
        let maxIndex = vectorLayerArr.length;
        for (let i = 0; i < maxIndex; i++) {
    
    
            let vectorLayer = vectorLayerArr.pop();
            if("PointLayer" === layerName && "PointLayer" === vectorLayer.get("name")){
    
    
                map.removeLayer(vectorLayer);
                break;
            }else if("CircleLayer" === layerName && "CircleLayer" === vectorLayer.get("name")) {
    
    
                map.removeLayer(vectorLayer);
                break;
            }else{
    
    
                map.removeLayer(vectorLayer);
            }
        }
}

export {
    
    map, renderPointLayer, renderCircleLayer, destoryVectorLayer, createAndRenderIconCanvasOverlay}  

注意:

  1. Icon 对象的如果需要引用本地的图片,必须先通过 import 导入才行,否则图片样式会找不到。导入方式详见代码第四行。
  2. 一定、一定、一定要充分利用官方示例和 API ~!!!
  3. 本文使用的坐标系为 Web_Mercator 这样方便绘制不定半径(单位:米)的圆,如果使用 WGS84 坐标系在绘制不定半径圆的时候,会因半径参数变为弧度增加绘制难度。
  4. 这里 有另外一些博主在开发过程中编写的代码包括 Quick Start 中介绍的非 Node 方式创建项目、加载天地图数据、在 WGS84 坐标系的地图中以米为单位绘制圆等。

源码

源码下载

有道无术,术尚可求;有术无道,止于术。

猜你喜欢

转载自blog.csdn.net/Supreme_Sir/article/details/105296872
今日推荐